Is it possible to generate a global list of marked strings at compile time/runtime?

大兔子大兔子 提交于 2020-01-02 18:23:03

问题


So, I'm working on translating my C++ app into multiple languages. What I'm currently using is something like:

#define TR(x) (lookupTranslatedString( currentLocale(), x ))
wcout << TR(L"This phrase is in English") << endl;

The translations are from a CSV file which maps the english string to the translated string.

"This phrase is in English","Nasa Tagalog itong pagsabi"

This is simplified, but that's the basic idea.

My question is about generating the list of English phrases that need to be translated. I just need the CSV with all the english phrases, and blank translated phrases. I was hoping that it might be possible to either generate this list at compile time or at runtime. At compiletime I was thinking something like this:

#define TR(x) \
    #warning x \
    (lookupTranslatedString( currentLocale(), x ))

and then maybe parse the compile log, or something. This seems not to work so well.

At runtime would also be great. I was thinking of just starting the app and having a hidden command that would dump the english CSV. I've seen similar methods used to register commands with a central list, using global variables. It might look something like this:

class TrString
{
public:
    static std::set< std::wstring > sEnglishPhrases;
    TrString( std::wstring english_phrase ) { sEnglishPhrases.insert( english_phrase ); }
};

#define TR(x) do {static TrString trstr(x);} while( false ); (lookupTranslatedString( currentLocale(), x ));

I know there's two problems with the above code. I doubt it compiles, but more importantly, in order to generate a list of all english phrases, I'd need to hit every single code path before accessing sEnglishPhrases.

It looks like I'll end up writing a small parser to read through all my code and look for TR strings, which isn't really that tough. I was just hoping to learn a little more about C++, and if there's a better way to do this.


回答1:


I think you're almost there. Taking the last idea:

class TrString
{
public:
    static std::set< std::string > sEnglishPhrases;
    std::string phrase;
    TrString(const std::string& english_phrase ):phrase(english_phrase)
    { sEnglishPhrases.insert( english_phrase ); }
    friend ostream &operator<<(ostream &stream, const TrString& o);
};

ostream &operator<<(ostream &stream, const TrString& o)
{
    stream << lookupTranslatedString( currentLocale(), o.phrase);
    return stream;
}

#define TR(x) ( TrString(x) )
// ...
std::cout << TR("This phrase is in English") << std::endl;

And as you say, you do need to run the code over every TR() statement, but you could configure a unit test framework to do this.

My alternative would be to use the above TrString class to make static variables for each module:

// unnamed namespace gives static instances
namespace
{
   TrString InEnglish("This phrase is in English");
   // ...
}

Now you just need to link in an alternative main() to print out TrString:: sEnglishPhrases




回答2:


You could just build a quick script to parse the file and strip what you need.

awk '/TR\(L"[^"]*")/ {print}' plop.c

If you need somthing slightly more complex then perl is your friend.




回答3:


What you're looking for seems very similar to what GNU gettext does. In particular, look at the xgettext tool.



来源:https://stackoverflow.com/questions/1369292/is-it-possible-to-generate-a-global-list-of-marked-strings-at-compile-time-runti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!