С++:Как локализовать уже написанную программу

StackOverflow https://stackoverflow.com/questions/1419342

  •  07-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

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

Это было полезно?

Решение 2

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

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

Два #define:

#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 триллионов файлов и добавить подчеркивания, как если бы я был обезьяной :/

Другие советы

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

// 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 потока.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top