C ++: как локализовать уже написанную программу - PullRequest
1 голос
/ 14 сентября 2009

Я хочу локализовать программу, которую я уже написал. Она довольно большая (почти 50 тыс. Строк), и в идеале мне нужна система, которая позволяет мне (программисту) выполнять наименьший объем работы без существенных изменений в программа - если возможно, вообще ничего.

Я посмотрел на gettext () и он мне очень понравился, но мне неясно, как он будет переводить такие строки:

const char *Colors[] = {
 { "Red" },
 { "Blue" },
 { "Yellow" },
 ....
};

которые ОЧЕНЬ распространены в моей программе. Здесь замена "Red" на gettext ("Red"), очевидно, не будет работать.

Так что я думал, что я сделаю что-то вроде OutputFunction (gettext (Colors [Id])), но тогда как мне получить список строк для локализации? Я сомневаюсь, что любая программа достаточно умна, чтобы иметь возможность получать «Красный», «Синий», «Желтый» из списка локализованных статически.

Поскольку в основном это сервер, нет необходимости изменять язык без перекомпиляции (я могу скомпилировать его для каждого поддерживаемого языка без каких-либо серьезных проблем или раздражений), я подумал о constexpr в C ++ 0x, идеально! Это будет работать в массивах / etc, и я легко получу список строк для локализации во время компиляции. Жаль, что ни один компилятор еще не реализовал это.

Смена всех строк на ID не возможна, поскольку это потребует огромных усилий с моей стороны, и особенно создание нового идентификатора для каждой новой строки будет чертовски неприятно. То же самое относится и к преобразованию всех массивов, подобных приведенному выше, во что-то другое.

Итак, есть идеи? : /

Ответы [ 2 ]

2 голосов
/ 14 сентября 2009

Для вашего конкретного примера я мог бы попробовать что-то вроде:

// presumably globals
const char *Colors_en[] = {
 { "Red" },
 { "Blue" },
 { "Yellow" },
 ....
};
const char *Colors[] = {0};

// in main()
gettextarray(Colors_en, Colors, sizeof(Colors_en) / sizeof(char*));

gettextarray вызывает gettext для каждого входа и записывает вывод. Я думаю, что это может быть реализовано так же, как вызов std :: transform. И вы могли бы избежать параметра размера с небольшим обманом шаблона.

Другим вариантом является вызов gettext в точке, где собирается использоваться любая из цветных строк (отображается или добавляется к строке для отображения). Это означает изменение большего количества кода, но не требует, чтобы main () переводил каждый набор строк в программе, прежде чем делать что-либо, что могло бы их использовать.

Если вы не хотите выполнять работу в main, вы можете сделать это в коде, который использует строки, что-то вроде этого:

if (Colors[0] == 0)
  gettextarray(Colors_en, Colors, sizeof(Colors_en) / sizeof(char*));

Или, если ваше приложение является многопоточным, рассмотрите pthread_once или эквивалент в используемом вами API потока.

1 голос
/ 14 сентября 2009

После долгой игры с gettext () и xgettext, я думаю, что сам нашел способ (извините, пока, но мне не понравился ваш подход. Должно быть сотни таких массивов, и мне придется импортировать все из них в main (), это много extern и много дополнительной работы: /).

В любом случае, я так думаю, теоретически это можно сделать (я еще не пытался на самом деле перевести, но не понимаю, почему это не сработает)

Два # определить:

#define _ gettext
#define __(x) x

Затем вы используете _ для фактического перевода и __, чтобы просто пометить строки как «для перевода»:

const char *Colors[] = {
 { __("Red") },
 { __("Blue") },
 { __("Yellow") },
 ....
};

void PrintColor(int id) {
    cout << _("The color is: ") << _(Colors[id]);
}

Затем вы запускаете:

xgettext -k_ -k__ *.cpp

И вы получите следующий .po файл:

#: test.cpp:2
msgid "Red"
msgstr ""

#: test.cpp:3
msgid "Blue"
msgstr ""

#: test.cpp:4
msgid "Yellow"
msgstr ""

#: test.cpp:9
msgid "The color is: "
msgstr ""

Итак, вы используете __ (или любое другое имя, на самом деле не имеет значения) в качестве «фиктивной функции», чтобы просто дать xgettext понять, что строка должна быть переведена, и _ чтобы фактически вызвать Gettext ().

Если вы вызываете _ со строкой, строка также будет помечена как переводимая, если вы вызовете ее с помощью переменной, массива, что бы тогда ни выглядело просто игнорируемым xgettext.

Отлично! Теперь все, что мне нужно сделать, это просмотреть 5 триллионов файлов и добавить подчеркивания, как будто я обезьяна: /

...