zHz00 Untitled

вторник, 10 апреля 2012
22:51 Как перевести интерфейс своей собственной программы
Описывается методика автоматизированного перевода интерфейса на другой язык
(читать далее)

Пожалуйста, ознакомьтесь с комментариями!

@темы: Программирование, Говнокод, Статьи

URL
Cегодня "летал" на воздушном шаре. Класс! Жаль ...
Ехали с дачи. Зашли в пять звезд. Прыщавый менеджер сказа...
В суете и спешке, в нескончаемой погоне за миражами, погр...
Кто-нибудь может мне подсказать, как установить пятый дел...
http://video.f1gp.ru/wtc.php3
http://swissposters.library.cmu.edu/Swiss/ У швейцарцев...

12.04.2012 в 10:52

12.04.2012 в 10:52
Ты зацепил сразу две проблемы: как делать правильно, и как к этому "правильно" придти.

Вторая проблема сложнее. Автоматический фокус, который ты описываешь, плох по ряду причин; его можно доводить до ума, но я считаю, что он всё равно никогда не будет достаточно хорош.
Во-первых, строки в коде программы дублирются. Автоматика никогда не будет точно определять, какая пара строк - дубль одной, а какая - одинаковые разные (по смыслу).
Во-вторых, автоматически сгенерированные идентификаторы всегда будут хуже даже корявых корейских "IsShouldFileOverwrite". А ведь со всеми этими __TEXT_SHOULD_OVERWRITE_FILE__1_ придётся жить, переносить их с места на место, придумывать (уже самому, а не автоматом) новые такие же... Нет, это слишком некрасиво.
В-третьих, строки не всегда генерируются простым образом. Строка может состоять из нескольких кусков, например: "Info: "+IntToStr(sprCount)+"sprites"\
"were drawn on"\
"the" + canvasName + "canvas".
Очевидно, что тупой метод вынесет даже кусочек "the" в отдельный ресурс, и даже умный метод всё равно не заменит это чудовище на удобный sprintf.
В чётвёртых, отличия всегда существуют не только в языке. Валюта пишется слева, а не справа, летоисчисление ведётся с рождения пророка Мухаммеда, строки пишутся справа налево, календарь считается с воскресенья, и ещё тысячи, тысячи мелочей. Я переводил программу на арабский и знаю.

В общем, моё решительное мнение - вводить в программу поддержку нескольких языков можно ТОЛЬКО вручную. Всё остальное - это как книгу промптом переводить, а потом руками дорабатывать. Ничего хорошего из этого не получится никогда.

Теперь что касается правильных методов. Это тема очень интересная. Хотелось бы найти такой способ локализации, чтобы и код читался нормально (без __TEXT_SHOULD_OVERWRITE_FILE__1_), и локализовывать было просто.

В винде стандартные механизмы локализации, на самом деле, очень неплохие. Главное, чтобы работу с ними поддерживал компилятор, тогда у нас не просто торт, а торт с вишенкой. Например, в Delphi можно сделать так:

resourcestring
sShouldOverwriteFile = "File already exists, should I overwrite it?"
...
MessageBox(..., sShouldOverwriteFile, ...);

Это, однако, не всегда возможно и не всегда удобно, а в некоторых языках не поддерживается. Поэтому часто делают вот так:

MessageBox(..., _s("ShouldOverwriteFile"), ...);

Где функция _s ищет строку с указанным текстовым идентификатором в файле перевода. Преимущества: файл строк с самого начала текстовый, его легко переводить и автоматическими средствами сравнивать, что во всех переводах один и тот же набор строк. Кроме того, устраняется лишний слой "номеров ресурсов" с дефайнами, а поиск по строковому идентификатору, в общем-то, лишь в пару раз медленней числового (несущественно).

Недостаток всех этих схем: что, если вообще все ресурсы пропали? И арабские, и английсские, и русские. Что показывать?

Функция _s() может, в конце концов, показать идентификатор "ShouldOverwriteFile" - это лучше, чем ничего, ведь он как-то похож на обозначаемую им строку. Конечно, пользователь ничего не поймёт, но программист сориентируется, где искать ошибку.

Интереснее сделали в Вордпрессе. Там рассудили: раз всё равно используется текстовый идентификатор, почему не сделать этим идентификатором саму строку в базовой локали?

MessageBox(..., _s("File already exists. Should I overwrite it?"), );

И если подумать, это очень неплохое решение. Скорость сравнения строк - затрата копеешная, зато в программе, во-первых, всегда будет базовая локаль, и во-вторых, практически не падает качество чтения кода. Плохо, конечно, то, что случайный лишний пробел в строке незаметно лишает её всех переводов.
URL

12.04.2012 в 11:10

12.04.2012 в 11:10
Спасибо. То, что ты написал в конце -- как раз и есть gettext.
> Я переводил программу на арабский и знаю.
Жеесть!

Часто о возможности локализации в начале не задумываются, а потом приходится всё разгребать. При этом не задумываются одни, а разгребают другие, иногда.

Хочу отметить, что при исходной английской локали читаемость __TEXT_SHOULD_OVERWRITE_FILE__1_ ненулевая.

В моём варианте файл перевода тоже текстовый, но с ресурсами приходится разбираться отдельно, так что придётся вручную добавить для каждой кнопки SetWindowText, если будет необходимость полного переключения на лету без перекомпиляции.
Да, что при использовании gettext при изменении исходных строк могут пропадать переводы я не подумал. Спасибо за указание на подводный камень в речке, к которой я только подошёл (ибо у меня стояла одноразовая задача; но грядёт многоразовая, и там я уже подумаю получше и подольше).
URL
Добавить комментарий

Расширенная форма

Подписаться на новые комментарии