Pull to refresh

Comments 30

Большое спасибо за статью, сразу в избранное и на дальнейшее более глубокое изучение на практике.
На мой взгляд бесполезная вещь, для интернационализации можно все слова и фразы интерфейса пользователя вынести в отдельный файл (к примеру, так сделано в punbb).
Зачем изобретать свою интернационализацию, если есть общепринятый формат, который будет удобнее и разработчику, и переводчику? Кроме того, скомпилированный файл .mo будет читаться куда быстрее просто текстового файла.
Спорный вопрос. Ведь если переводчик не будет видеть результат своего труда (вряд ли сам переводчик будет компилировать файл), то результат перевода будет удручающий (смотрите об отзывах перевода каких-нибудь пиратских игр). Решением может быть проверка корректности перевода в приложении.
Языки питон, РНР, ruby, perl имеют свои форматы словарей или хеш-массивов. Например кусок кода на РНР:
$lang_delete = array(
'Delete post'			=>	'Delete post',
'Warning'				=>	'Warning! If this is the first post in the topic, the whole topic will be deleted.',
'Delete'				=>	'Delete',	// The submit button
'Post del redirect'		=>	'Post deleted. Redirecting …',
'Topic del redirect'		=>	'Topic deleted. Redirecting …'

Переводчики настолько глупы, что после объяснения что переводить они впадут в ступор?
P.S. Если говорить про питон, то неужели скомпелированный файл .mo будет потреблять меньше ресурсов по сравнению с .pyc?
Просто в этом случае придётся изобретать свой велосипед по хранению данных, переводу на разные языки, определению локалей… да даже по поиску в исходниках строк, которые надо переводить.

Придётся изобретать свой формат/процедуру обмена данными с переводчиком — при том что для .po существует тот же Poedit, а в нём, например, существует Translation memory (которым, в том или ином виде, будет вынужден пользоваться любой переводчик для значительных объёмов переводимых данных).

В случае escapable данных для .po-файлов этим займётся специально обученный редактор; при переводе же «прямо в исходниках» переводчику, возможно, придётся объяснять совершенно не нужные ему правила эскейпинга для используемого языка программирования.

Не, я нисколько не против — можно изобрести и реализовать любой формат и инфраструктуру перевода — хоть в SQL-е хранить XML-документы с соответствиями фраз переводам.
А можно взять уже готовый фреймворк и сэкономленное время потратить на улучшение бизнес-логики.
Кстати, обратите внимание, как делаются переводы в опенсорс-проектах (в том же Debian). Есть команды переводчиков на разные языки, и они переводят все программы; они вполне получают feedback, ибо способны запускать эти программы и видеть, в какой момент там появляется соответствующее значение; но требовать от них знания особенностей синтаксиса C, C++, Perl, Python, TCL, Lua, bash, C#, Java, Ruby, PHP… было бы неразумно. У них есть более важные дела. Программы переводить.
Соглашусь с вами, видимо до таких проектов еще не дорос, чтобы о них говорить.
Немного опоздал с ответом, но все же напишу.

Да, действительно можно хранить строки в словаре и написать функцию, которая будет получать переведенную строку по ключу, можно добавить поддержку загрузки разных файлов для разных локалей, но зачем, если все это уже умеет gettext?:)

Да и, как упоминалось выше, переводчик не обязан знать язык, на котором программа, да и вообще он может вообще не быть программистом. Кроме того, потенциальный переводчик наверняка пользуется Poedit или каким-нибудь текстовым редактором с бандлом или плагином для работы с gettext, а тут ему придется работать с неизвестным форматом и возможно даже в другой программе.

Получается, что велосипед не выгоден и программисту (время на написание/отловку багов/дописывание забытых фич), и переводчику (непривычный синтаксис и среда)
Подобный подход таит в себе несколько подводных камней:

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

Во-вторых, когда строки вынесены, идентификаторы придуманы, а вы вдруг хотите поменять то или иное сообщение, то вам необходимо проследить все использования этого идентификатора так, чтобы изменение этого сообщения не повлекло негативного side-effect-а в других частях программы. Это, помимо дополнительной работы, снижает гибкость подсистемы перевода и заставляет программиста заниматься дополнительной рутиной, отвлекаясь от основной задачи и тратя драгоценное время и внимание впустую.

gettext же прекрасно справляется как с автоматизированным извлечением переводимых строк, так и с трэкингом их изменений, склеиванием и расклеиванием разничных строк и обновлением существующего перевода так, чтобы он всегда содержал актуальные данные (не убивая при этом сделанные ранее переводы).

В итоге программист занимается программированием, а переводчик — переводом, не мешая друг другу.
Gettext действительно полезная вещь. Сейчас как раз занимаюсь интернационализацией одной своей программки и пока столкнулась только с одной неприятной вещью, как раз указанное автором «перевод отдельных слов и шаблонов предложений в нём делать опасно». Когда одно и то же английское слово в разных местах интерфейса надо по разному перевести на русский (например, name — имя и название) возникает проблема. Пока выкручиваюсь, добавляя в текст програмы какие-либо различия для этих слов (например name1 и name2) и создавая отдельный файл переводов для английского, где они снова сводятся в одно.
Gettext достаточно гибок, чтобы можно было обработать и этот случай.

В таких случаях используется контекстный перевод. Реализуется дополнительный метод(например _с()), который принимает фразы в формате "|" разделитель для контекста можно выбрать естественно любой. Затем, если вы пользуетесь xgettext неполохо написать небольшой скрипт, который перед передачей питоньих файлов в xgettext заменяет все вызовы _с() на _() и обратно после прохода xgettext(я для этого использую sed), можно просто бэкапить файл рядом и переписывать потом его назад.

В результате в pot и po файлы попадают строки с контекстом, которые вы уже переводите в соответствующем контексте. Например вот строки для имени личности и имени какой-либо другой сущности: «name|person» «name|enitity», которые можно перевести на русский по-разному.

Опять же использовать дополнительный метод или нет это уже дело вкуса. Как правило он нужен только для того, чтобы вырезать контекст из непереведённых фраз так, чтобы он не попадал в юзер интерфейс. Опять же это накладывает оверхэд из-за того, что требуется препроцессить каждую строку помеченную для перевода таким образом. Как вариант можно не реализовывать этот метод, а просто переводить английские фразы с контекстом в те же самые фразы без контекста.
извините забыл, что тэги обрабатываются:
… который принимает фразы в формате "<phrase>|<context>" разделитель…
Ну, в принципе ваш вариант «без реализации метода» я и использую, только не догадалась до такого красивого синтаксиса :) Пожалуй, можно и переделать, пока не поздно — так выглядит логичнее и удобнее.
Кстати как бы я отрицательно я не относился к Wordpress, но это решение я нашёл именно в его коде.
gettext еще более гибок, чем вы считаете. У него есть готовая функция на этот счет:
gettext.dgettext(domain, message)
Like gettext(), but look the message up in the specified domain.

Естесственно, ее можно забиндить на то же _d(), и это займет ровно одну строчку кода.
Так что же всё-таки делать с падежами?
… и с числами. Знаю, есть поддержка, но если бы вы привели пример, было бы совсем хорошо.
Есть возможность указания вида фразы в единственном и множественном числе для одного варианта перевода. Поддержки падежей нет, gettext не знает про грамматику и синтаксис русского или любого другого языка. Переводимой единицей для gettext является не слово, а фраза целиком. Частично можно реализовать, используя дополнительно pytils.
Спасибо за pytils — интересная вещь.
Не в курсе, в ней можно так же в отдельный файл вынести переводы?
На сколько я помню — нет. Документация в репозитории проекта — посмотрите.
Сейчас некогда, но если тема актуальна, то ближе к выходным могу сделать статью о том, как при помощи того же gettext управляться с падежами, не привлекая для этого сторонние утилиты.

Думаете, подобное руководство будет востребовано?
Думаю, да, раз уж эта статья с самыми основами попала на главную :) Подробностей про gettext в виде статей не слишком много, больше крупинки информации по форумам, отсылки в гугл и документацию. Вот тут говорят — надо переводить фразами, но есть ведь меню и заголовки таблиц, где без падежей ещё кое-как, но без родов бывает тяжко. Есть, правда, вариант делать исходники на языке со сложной грамматикой (падежами, родами и т.д.), а потом уже переводить на английский. Но, например, в опенсорсе это не прокатит 100%. Есть возможность использовать «контекст», как выше предлагает siasia, но если есть более красивое решение — это очень интересно.
Было бы очень полезно и интересно.
UFO just landed and posted this here
сталкивался с проблемой, в веб приложениях (или когда один процесс обрабатывает несколько запросов параллельно) gettext бесполезен, так как переключение локали идет через переменную окружения LANG и
переключение в одном потоке, переключает локаль во всех :-(
Видимо что-то было не так со структурой вашего приложения, а скорее всего вы что-то путаете. Gettext успешно используется во многих web-фреймворках как основной инструмент реализации i18n.
Еще можно добавить, что следующие варианты равнозначны:

print _("%s had a little %s") % (name, animal)
print _("%(name)s had a little %(animal)s") % dict(name=name, animal=animal)

При этом первый вариант сломается в некоторых языках, если порядок слов меняется из-за особенностей грамматики; второй же вариант в худшем случае будет выглядеть коряво, но смысл сохранится.
Угу. Но, разумеется, переводить уже надо будет строку "%(name)s had a little %(animal)s".

Вообще, это начинает быть полезно с того момента, как появляются те самые ситуации, «если порядок слов меняется из-за особенностей грамматики». Поэтому к абсолютному разделению труда программиста и переводчика стремиться особо не стоит — для взаимного удобства будет лучше, если они сотрудничают и способны влиять на решения друг друга. Чтобы переводчик мог сообщить программисту о проблеме с порядком слов, падежами, ещё какими особенностями языка (возможно, совершенно неизвестными программисту).
В идеале — да, надо сотрудничать. На практике часто сначала пишется программа (на английском и, возможно, с переводом на второй язык, родной для автора), а затем она постепенно обрастает переводами. Чтобы из-за очередного перевода не пришлось править код программы, разумно просто использовать словари во всех случаях, когда переменных несколько.
Sign up to leave a comment.

Articles