Комментарии 30
Большое спасибо за статью, сразу в избранное и на дальнейшее более глубокое изучение на практике.
+1
На мой взгляд бесполезная вещь, для интернационализации можно все слова и фразы интерфейса пользователя вынести в отдельный файл (к примеру, так сделано в punbb).
-13
Зачем изобретать свою интернационализацию, если есть общепринятый формат, который будет удобнее и разработчику, и переводчику? Кроме того, скомпилированный файл .mo будет читаться куда быстрее просто текстового файла.
+5
Спорный вопрос. Ведь если переводчик не будет видеть результат своего труда (вряд ли сам переводчик будет компилировать файл), то результат перевода будет удручающий (смотрите об отзывах перевода каких-нибудь пиратских игр). Решением может быть проверка корректности перевода в приложении.
Языки питон, РНР, ruby, perl имеют свои форматы словарей или хеш-массивов. Например кусок кода на РНР:
Переводчики настолько глупы, что после объяснения что переводить они впадут в ступор?
P.S. Если говорить про питон, то неужели скомпелированный файл .mo будет потреблять меньше ресурсов по сравнению с .pyc?
Языки питон, РНР, 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?
-3
Просто в этом случае придётся изобретать свой велосипед по хранению данных, переводу на разные языки, определению локалей… да даже по поиску в исходниках строк, которые надо переводить.
Придётся изобретать свой формат/процедуру обмена данными с переводчиком — при том что для .po существует тот же Poedit, а в нём, например, существует Translation memory (которым, в том или ином виде, будет вынужден пользоваться любой переводчик для значительных объёмов переводимых данных).
В случае escapable данных для .po-файлов этим займётся специально обученный редактор; при переводе же «прямо в исходниках» переводчику, возможно, придётся объяснять совершенно не нужные ему правила эскейпинга для используемого языка программирования.
Не, я нисколько не против — можно изобрести и реализовать любой формат и инфраструктуру перевода — хоть в SQL-е хранить XML-документы с соответствиями фраз переводам.
А можно взять уже готовый фреймворк и сэкономленное время потратить на улучшение бизнес-логики.
Придётся изобретать свой формат/процедуру обмена данными с переводчиком — при том что для .po существует тот же Poedit, а в нём, например, существует Translation memory (которым, в том или ином виде, будет вынужден пользоваться любой переводчик для значительных объёмов переводимых данных).
В случае escapable данных для .po-файлов этим займётся специально обученный редактор; при переводе же «прямо в исходниках» переводчику, возможно, придётся объяснять совершенно не нужные ему правила эскейпинга для используемого языка программирования.
Не, я нисколько не против — можно изобрести и реализовать любой формат и инфраструктуру перевода — хоть в SQL-е хранить XML-документы с соответствиями фраз переводам.
А можно взять уже готовый фреймворк и сэкономленное время потратить на улучшение бизнес-логики.
+1
Кстати, обратите внимание, как делаются переводы в опенсорс-проектах (в том же Debian). Есть команды переводчиков на разные языки, и они переводят все программы; они вполне получают feedback, ибо способны запускать эти программы и видеть, в какой момент там появляется соответствующее значение; но требовать от них знания особенностей синтаксиса C, C++, Perl, Python, TCL, Lua, bash, C#, Java, Ruby, PHP… было бы неразумно. У них есть более важные дела. Программы переводить.
0
Немного опоздал с ответом, но все же напишу.
Да, действительно можно хранить строки в словаре и написать функцию, которая будет получать переведенную строку по ключу, можно добавить поддержку загрузки разных файлов для разных локалей, но зачем, если все это уже умеет gettext?:)
Да и, как упоминалось выше, переводчик не обязан знать язык, на котором программа, да и вообще он может вообще не быть программистом. Кроме того, потенциальный переводчик наверняка пользуется Poedit или каким-нибудь текстовым редактором с бандлом или плагином для работы с gettext, а тут ему придется работать с неизвестным форматом и возможно даже в другой программе.
Получается, что велосипед не выгоден и программисту (время на написание/отловку багов/дописывание забытых фич), и переводчику (непривычный синтаксис и среда)
Да, действительно можно хранить строки в словаре и написать функцию, которая будет получать переведенную строку по ключу, можно добавить поддержку загрузки разных файлов для разных локалей, но зачем, если все это уже умеет gettext?:)
Да и, как упоминалось выше, переводчик не обязан знать язык, на котором программа, да и вообще он может вообще не быть программистом. Кроме того, потенциальный переводчик наверняка пользуется Poedit или каким-нибудь текстовым редактором с бандлом или плагином для работы с gettext, а тут ему придется работать с неизвестным форматом и возможно даже в другой программе.
Получается, что велосипед не выгоден и программисту (время на написание/отловку багов/дописывание забытых фич), и переводчику (непривычный синтаксис и среда)
0
Подобный подход таит в себе несколько подводных камней:
Во-первых, вынося строки в отдельный файл, необходимо поддерживать его в актуальном состоянии и выдумывать каждый раз уникальные идентификаторы для каждой из фраз. Это создает дополнительную работу.
Во-вторых, когда строки вынесены, идентификаторы придуманы, а вы вдруг хотите поменять то или иное сообщение, то вам необходимо проследить все использования этого идентификатора так, чтобы изменение этого сообщения не повлекло негативного side-effect-а в других частях программы. Это, помимо дополнительной работы, снижает гибкость подсистемы перевода и заставляет программиста заниматься дополнительной рутиной, отвлекаясь от основной задачи и тратя драгоценное время и внимание впустую.
gettext же прекрасно справляется как с автоматизированным извлечением переводимых строк, так и с трэкингом их изменений, склеиванием и расклеиванием разничных строк и обновлением существующего перевода так, чтобы он всегда содержал актуальные данные (не убивая при этом сделанные ранее переводы).
В итоге программист занимается программированием, а переводчик — переводом, не мешая друг другу.
Во-первых, вынося строки в отдельный файл, необходимо поддерживать его в актуальном состоянии и выдумывать каждый раз уникальные идентификаторы для каждой из фраз. Это создает дополнительную работу.
Во-вторых, когда строки вынесены, идентификаторы придуманы, а вы вдруг хотите поменять то или иное сообщение, то вам необходимо проследить все использования этого идентификатора так, чтобы изменение этого сообщения не повлекло негативного side-effect-а в других частях программы. Это, помимо дополнительной работы, снижает гибкость подсистемы перевода и заставляет программиста заниматься дополнительной рутиной, отвлекаясь от основной задачи и тратя драгоценное время и внимание впустую.
gettext же прекрасно справляется как с автоматизированным извлечением переводимых строк, так и с трэкингом их изменений, склеиванием и расклеиванием разничных строк и обновлением существующего перевода так, чтобы он всегда содержал актуальные данные (не убивая при этом сделанные ранее переводы).
В итоге программист занимается программированием, а переводчик — переводом, не мешая друг другу.
0
Gettext действительно полезная вещь. Сейчас как раз занимаюсь интернационализацией одной своей программки и пока столкнулась только с одной неприятной вещью, как раз указанное автором «перевод отдельных слов и шаблонов предложений в нём делать опасно». Когда одно и то же английское слово в разных местах интерфейса надо по разному перевести на русский (например, name — имя и название) возникает проблема. Пока выкручиваюсь, добавляя в текст програмы какие-либо различия для этих слов (например name1 и name2) и создавая отдельный файл переводов для английского, где они снова сводятся в одно.
+1
Gettext достаточно гибок, чтобы можно было обработать и этот случай.
В таких случаях используется контекстный перевод. Реализуется дополнительный метод(например _с()), который принимает фразы в формате "|" разделитель для контекста можно выбрать естественно любой. Затем, если вы пользуетесь xgettext неполохо написать небольшой скрипт, который перед передачей питоньих файлов в xgettext заменяет все вызовы _с() на _() и обратно после прохода xgettext(я для этого использую sed), можно просто бэкапить файл рядом и переписывать потом его назад.
В результате в pot и po файлы попадают строки с контекстом, которые вы уже переводите в соответствующем контексте. Например вот строки для имени личности и имени какой-либо другой сущности: «name|person» «name|enitity», которые можно перевести на русский по-разному.
Опять же использовать дополнительный метод или нет это уже дело вкуса. Как правило он нужен только для того, чтобы вырезать контекст из непереведённых фраз так, чтобы он не попадал в юзер интерфейс. Опять же это накладывает оверхэд из-за того, что требуется препроцессить каждую строку помеченную для перевода таким образом. Как вариант можно не реализовывать этот метод, а просто переводить английские фразы с контекстом в те же самые фразы без контекста.
В таких случаях используется контекстный перевод. Реализуется дополнительный метод(например _с()), который принимает фразы в формате "|" разделитель для контекста можно выбрать естественно любой. Затем, если вы пользуетесь xgettext неполохо написать небольшой скрипт, который перед передачей питоньих файлов в xgettext заменяет все вызовы _с() на _() и обратно после прохода xgettext(я для этого использую sed), можно просто бэкапить файл рядом и переписывать потом его назад.
В результате в pot и po файлы попадают строки с контекстом, которые вы уже переводите в соответствующем контексте. Например вот строки для имени личности и имени какой-либо другой сущности: «name|person» «name|enitity», которые можно перевести на русский по-разному.
Опять же использовать дополнительный метод или нет это уже дело вкуса. Как правило он нужен только для того, чтобы вырезать контекст из непереведённых фраз так, чтобы он не попадал в юзер интерфейс. Опять же это накладывает оверхэд из-за того, что требуется препроцессить каждую строку помеченную для перевода таким образом. Как вариант можно не реализовывать этот метод, а просто переводить английские фразы с контекстом в те же самые фразы без контекста.
+1
извините забыл, что тэги обрабатываются:
… который принимает фразы в формате "<phrase>|<context>" разделитель…
… который принимает фразы в формате "<phrase>|<context>" разделитель…
0
Ну, в принципе ваш вариант «без реализации метода» я и использую, только не догадалась до такого красивого синтаксиса :) Пожалуй, можно и переделать, пока не поздно — так выглядит логичнее и удобнее.
0
gettext еще более гибок, чем вы считаете. У него есть готовая функция на этот счет:
Естесственно, ее можно забиндить на то же _d(), и это займет ровно одну строчку кода.
gettext.dgettext(domain, message)
Like gettext(), but look the message up in the specified domain.
Естесственно, ее можно забиндить на то же _d(), и это займет ровно одну строчку кода.
0
Так что же всё-таки делать с падежами?
+3
… и с числами. Знаю, есть поддержка, но если бы вы привели пример, было бы совсем хорошо.
+2
Есть возможность указания вида фразы в единственном и множественном числе для одного варианта перевода. Поддержки падежей нет, gettext не знает про грамматику и синтаксис русского или любого другого языка. Переводимой единицей для gettext является не слово, а фраза целиком. Частично можно реализовать, используя дополнительно pytils.
+2
Сейчас некогда, но если тема актуальна, то ближе к выходным могу сделать статью о том, как при помощи того же gettext управляться с падежами, не привлекая для этого сторонние утилиты.
Думаете, подобное руководство будет востребовано?
Думаете, подобное руководство будет востребовано?
+2
Думаю, да, раз уж эта статья с самыми основами попала на главную :) Подробностей про gettext в виде статей не слишком много, больше крупинки информации по форумам, отсылки в гугл и документацию. Вот тут говорят — надо переводить фразами, но есть ведь меню и заголовки таблиц, где без падежей ещё кое-как, но без родов бывает тяжко. Есть, правда, вариант делать исходники на языке со сложной грамматикой (падежами, родами и т.д.), а потом уже переводить на английский. Но, например, в опенсорсе это не прокатит 100%. Есть возможность использовать «контекст», как выше предлагает siasia, но если есть более красивое решение — это очень интересно.
0
Было бы очень полезно и интересно.
0
НЛО прилетело и опубликовало эту надпись здесь
japanesetranslator.co.uk/your-name-in-japanese/?forename=Mary&style=0
Возможно, потому что в английском произношении там дифтонг, превратившийся в японском в сочетание двух символов катаканы.
(транскрипция в лингво)
Возможно, потому что в английском произношении там дифтонг, превратившийся в японском в сочетание двух символов катаканы.
(транскрипция в лингво)
0
сталкивался с проблемой, в веб приложениях (или когда один процесс обрабатывает несколько запросов параллельно) gettext бесполезен, так как переключение локали идет через переменную окружения LANG и
переключение в одном потоке, переключает локаль во всех :-(
переключение в одном потоке, переключает локаль во всех :-(
0
Еще можно добавить, что следующие варианты равнозначны:
При этом первый вариант сломается в некоторых языках, если порядок слов меняется из-за особенностей грамматики; второй же вариант в худшем случае будет выглядеть коряво, но смысл сохранится.
print _("%s had a little %s") % (name, animal) print _("%(name)s had a little %(animal)s") % dict(name=name, animal=animal)
При этом первый вариант сломается в некоторых языках, если порядок слов меняется из-за особенностей грамматики; второй же вариант в худшем случае будет выглядеть коряво, но смысл сохранится.
+4
Угу. Но, разумеется, переводить уже надо будет строку
Вообще, это начинает быть полезно с того момента, как появляются те самые ситуации, «если порядок слов меняется из-за особенностей грамматики». Поэтому к абсолютному разделению труда программиста и переводчика стремиться особо не стоит — для взаимного удобства будет лучше, если они сотрудничают и способны влиять на решения друг друга. Чтобы переводчик мог сообщить программисту о проблеме с порядком слов, падежами, ещё какими особенностями языка (возможно, совершенно неизвестными программисту).
"%(name)s had a little %(animal)s"
.Вообще, это начинает быть полезно с того момента, как появляются те самые ситуации, «если порядок слов меняется из-за особенностей грамматики». Поэтому к абсолютному разделению труда программиста и переводчика стремиться особо не стоит — для взаимного удобства будет лучше, если они сотрудничают и способны влиять на решения друг друга. Чтобы переводчик мог сообщить программисту о проблеме с порядком слов, падежами, ещё какими особенностями языка (возможно, совершенно неизвестными программисту).
0
В идеале — да, надо сотрудничать. На практике часто сначала пишется программа (на английском и, возможно, с переводом на второй язык, родной для автора), а затем она постепенно обрастает переводами. Чтобы из-за очередного перевода не пришлось править код программы, разумно просто использовать словари во всех случаях, когда переменных несколько.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Международные ягнята