Можно ли создать глобальный список отмеченных строк во время компиляции/время выполнения?

Итак, я работаю над переводом своего приложения C++ на несколько языков. В настоящее время я использую что-то вроде:

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

Переводы взяты из файла CSV, который сопоставляет английскую строку с переведенной строкой.

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

Это упрощенно, но это основная идея.

Мой вопрос касается создания списка английских фраз, которые необходимо перевести. Мне просто нужен CSV со всеми английскими фразами и пустыми переведенными фразами. Я надеялся, что можно будет сгенерировать этот список либо во время компиляции, либо во время выполнения. Во время компиляции я думал примерно так:

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

а затем, возможно, разобрать журнал компиляции или что-то в этом роде. Кажется, это не так хорошо работает.

Во время выполнения также было бы здорово. Я думал просто запустить приложение и иметь скрытую команду, которая выгружала бы английский CSV. Я видел похожие методы, используемые для регистрации команд в центральном списке с использованием глобальных переменных. Это может выглядеть примерно так:

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 ));

Я знаю, что есть две проблемы с приведенным выше кодом. Я сомневаюсь, что он компилируется, но, что более важно, для создания списка всех английских фраз мне нужно будет пройти каждый путь кода, прежде чем обращаться к sEnglishPhrases.

Похоже, я закончу тем, что напишу небольшой синтаксический анализатор, который будет читать весь мой код и искать строки TR, что на самом деле не так уж сложно. Я просто надеялся узнать немного больше о С++ и узнать, есть ли лучший способ сделать это.


person tfinniga    schedule 02.09.2009    source источник


Ответы (3)


Я думаю, ты почти у цели. Возьмем последнюю идею:

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;

И, как вы говорите, вам нужно запускать код для каждого оператора TR(), но для этого вы можете настроить структуру модульного тестирования.

Моей альтернативой было бы использование вышеуказанного класса TrString для создания статических переменных для каждого модуля:

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

Теперь вам просто нужно добавить альтернативную ссылку main(), чтобы распечатать TrString::sEnglishPhrases

person quamrana    schedule 02.09.2009
comment
Похоже, речь идет о лучшем решении, то есть действительно чистого решения не существует. Я думаю, это имеет смысл, так как все, кого я видел, от gettext до Qt, просто реализуют небольшой синтаксический анализатор. - person tfinniga; 03.09.2009

Вы можете просто создать быстрый скрипт для анализа файла и удаления того, что вам нужно.

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

Если вам нужно что-то более сложное, то Perl — ваш друг.

person Martin York    schedule 02.09.2009
comment
Да, похоже, это то, чем я в конечном итоге займусь. Мне просто интересно, есть ли лучший способ. - person tfinniga; 02.09.2009

То, что вы ищете, очень похоже на то, что делает GNU gettext. . В частности, обратите внимание на инструмент xgettext.

person Éric Malenfant    schedule 02.09.2009