Специалист по локализации
0,0
рейтинг
14 января 2013 в 13:05

Разработка → Пара слов об интернационализации приложений из песочницы

Я давно регулярно читаю Хабр и заметил, что здесь довольно мало внятных статей о локализации ПО, ориентированных на разработчиков. По своему опыту управления проектами локализации я могу сказать, что локализация — это не только перевод строк и адаптация приложения к контексту той или иной страны, но и постоянное противоборство (в идеальных случаях — равноправное взаимодействие) с разработчиками.
В этой статье я постараюсь на примере показать, как можно создать так называемый localization-friendly code, то есть, организовать ресурсы таким образом, чтобы существенно облегчить локализацию приложения, снизив избыточные временные и финансовые затраты.
Сразу же оговорюсь, что речь пойдёт в первую очередь об интернационализации, то есть, об учёте всех лингвистических особенностей на этапе разработки. Если же ресурсы вашего проекта изначально не подразумевали локализацию, а впоследствии вы решились на неё, то их «затачивание» под локализацию может выйти намного дороже, чем доход от неё.




Используйте Unicode


В большинстве случаев вопрос о кодировке UTF-8 (или UTF-16) встаёт при планировании локализации на азиатские языки, где количество символов может достигать нескольких тысяч. Даже если в данный момент локализация на корейский или китайский языки не планируется, стоит позаботиться об универсальной кодировке заранее. Если стратегия локализации вашего продукта изменится, то перескакивать на ходу на другую кодировку будет намного сложнее. Совет: для всех ресурсов используйте Unicode по умолчанию, даже если проект пока только на русском/английском/любом другом языке.
Кстати, например, спецификации JSON и YAML (эти форматы нередко используются для хранения локализуемых ресурсов) предписывают использование Unicode.

Позаботьтесь о шрифтах


Эта, вроде бы мелочь, часто является критичным фактором, тормозящим локализацию. Убедитесь, что используемые вами шрифты имеют символы для языков локализации (в первую очередь, опять же, азиатские языки, а также иврит, арабский и диакритика европейских языков).
Помните, что
ä, à или ą ≠ a
также как и в русском «е» не всегда равно «ё».
В моей практике был случай, когда разработчики сами нарисовали шрифт, содержащий набор букв только для английского языка. Когда дело дошло до локализации на немецкий и польский языки, им пришлось дорисовывать буквы с диакритическими знаками.

Оставляйте пространство для манёвра


Помимо шрифтов перевод текстов приложения готовит ещё один подводный камень для вёрстки.
Сравните, как может переводиться один пункт меню на разные языки

ru: Сохранить как
en: Save as
fi: Tallenna nimellä
zh: 另存为

Если для китайского языка нам потребуется всего 3 символа, то для финского уже целых 16! Кроме того, помимо количества символов важны также особенности того или иного шрифта.

Сравним финскую и китайскую строку по длине (шрифт для обоих языков Arial Unicode MS, 12 кегль) — финский текст (114 пикселей) в 2,5 раза длиннее китайского (45 пикселей).
Поэтому в элементах интерфейса очень важно иметь место про запас, чтобы исключить обрезание отображаемого текста. Если в определённых случаях места не хватает, можно использовать автоматическую подгонку текста по размеру. Однако это решение приведёт к тому, что в разных элементах интерфейса с большой вероятностью будет отображаться текст разного размера.

Псевдолокализация


Увидеть проблемные места до начала перевода поможет такой приём как псевдолокализация. Она является одним из методов тестирования приложений для проверки их готовности к локализации. Суть её заключается в том, что вместо перевода в ресурсы подставляется текст на псевдоязыке, созданный по специальному алгоритму (зависит от используемого программного обеспечения). Самый примитивный пример: вместо английского текста подставляется транслитерация/транскрипция кириллическими буквами:
Save as -> Саве ас
Save as -> Сэйв аз
Такой метод позволяет проверить следующие моменты:
  • корректно ли отображаются диакритические знаки (например, немецкий, польский);
  • корректно ли отображаются языки с другими шрифтами (например, китайский, русский);
  • есть ли проблемы с отображением элементов интерфейса для языков с направлением текста справа налево (например, арабский);
  • есть ли проблемы с отображением нестандартных символов (например, в именах пользователей);
  • все ли локализуемые ресурсы извлечены в отдельные файлы (использование текста прямо в коде несёт в себе массу проблем, см. ниже про хардкодинг).


При псевдолокализации нередко используют машинный перевод на нужный язык. С одной стороны, это простое решение в случае отсутствия специальных средств для генерации псевдоперевода. С другой стороны, я уже не раз видел, как разработчики путали локализованные ресурсы с псевдолокализованными и даже по недосмотру заменяли нормальный перевод машинным в репозиториях. Кроме того, машинный перевод не всегда позволяет оценить отображение всех символов языка (например, буква œ не так часто встречается в текстах, но её отображение тоже необходимо протестировать).
Например, так выглядит интерфейс плагина псевдоперевода в программе memoQ:


А вот так выглядит результат с этими настройками:


Внешние ресурсы


Для того, чтобы иметь полный обзор локализуемых материалов, необходимо отделить все ресурсы от кода. Мультимедийную информацию, содержащую текст (чаще всего это изображения, а также видео и аудио, например, в играх), следует также хранить отдельно, с сортировкой по локалям. Во-первых, это существенно упростит работу создателям контента, им не нужно будет копаться в коде, чтобы исправить какое-нибудь системное сообщение. Во-вторых, это позволит менеджеру по локализации точно рассчитать сроки и бюджет для каждого языка. В-третьих, это позволит быть несравнимо гибкими в работе с многоязычным контентом.
Наиболее популярными форматами для обмена локализуемыми данными являются XLIFF и .po-файлы. Так или иначе современные системы автоматизированного перевода в состоянии преобразовывать любые файлы в понятные переводчикам форматы.
Google и Apple тоже настоятельно советуют разработчикам извлекать все ресурсы для локализации во вне: рекомендации для разработчиков под Android, рекомендации Apple по интернационализации.

Хардкодинг в интернационализации


В продолжение предыдущего пункта стоить рассказать о важном моменте. Локализация подразумевает не только перевод слов, но и адаптацию чисел, единиц измерения, форматов даты и времени, а также знаков препинания к локальным стандартам.

Знаки препинания

Многие разработчики любят «зашивать» знаки препинания в код, думая, что точки и вопросительные знаки-то уж точно во всех языках одинаковые. Но сравните:

ru:
Вы уверены?

en:
Are you sure?

fr:
Êtes-vous sûr ?

es:
¿Está seguro?

ar:
هل أنت متأكد؟


Во французском языке вопросительный знак отделяется пробелом (кстати говоря, Хабр пробел перед знаком вопроса упорно убирал, пришлось колдовать с тегами). В испанском вопросительный знак состоит из перевёрнутого в начале и обычного в конце фразы, а в арабском он вообще стоит слева и обращён в другую сторону. Если вопросительный знак будет подставляться из кода, то не всем пользователям будет комфортно читать такое сообщение (разве что в коде не будет прописана зависимость от локали, но зачем такие извращения?).

Помимо знаков препинания, нужно быть осторожными с пробелами, доверяя коду их принудительную вставку. Ведь есть языки, где пробелы между словами не используются — например, японский.
Говорят, что локализация японских или китайских приложений на европейские языки может стать сущим адом, если разработчики не учли нюанс, что другие языки разделяют слова пробелами.
Итак, пунктуация является частью текста и её следует выносить во внешние ресурсы.

Числа

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

ru: 18 765,22
en: 18,765.22
de: 18.765,22
he: 18,765.22
el: 18.765,22
fa: 18٫765.22

Обратите внимание, какой символ используется в качестве тысячных и дробных разделителей. В английском языке и иврите точка и запятая стоят совсем иначе, чем в немецком и греческом языках. А в русском языке в качестве тысячного разделителя для чисел >9999 используется пробел (неразрывный). А в фарси тысячи разделяются особым символом «моммайе» (U+066B), однако особого стандарта для этого языка нет, разделителям могут быть также и запятая, и пробел.
Можно, конечно, считать, что это мелочи и «кому надо, и в таком виде поймут». Однако такие мелочи иногда могут привести к серьёзным недопониманиям, особенно, когда речь идёт о ценах или важных инженерных расчётах.
Кстати, о ценах, давайте сравним:

ru: 2,25 €
en: €2.25
de-at: € 2,25
de-de: 2,25 €
lv: € 2,25
lt: 2,25 €

В разных языках знаки валюты располагаются по-разному, из чего следует вывод, что хардкодить эти символы тоже лучше не стоит. Причём, как вы видите, нормы различаются не только среди языков, но и среди языковых вариантов (в Австрии и Германии). Даже соседние Латвия и Литва имеют различные нормы.

Единицы измерения

Иногда приходится адаптировать к национальным стандартам не только внешний вид числа, но и само число. Речь идёт о единицах измерения. Если они используются в вашем проекте, то всегда следует узнать, какая система принята в той или иной стране, чтобы понятно сообщать пользователю о скорости, длине, массе, температуре и пр.
Сообщение «Вы движетесь со скоростью 62 мили в час» ни о чём не скажет водителю из Пскова. Также как сообщение «Вы движетесь со скоростью 100 километров в час» может привести в ступор водителя из Чикаго.
В таком случае недостаточно просто отдавать числовую переменную, следует копать глубже и изменять формулу расчёта в зависимости от локали. Правда, идеальным решением будет всё-таки предоставить выбор системы измерения пользователю в настройках приложения, сделав эту настройку независимой от локали. В любом случае, локальные единицы измерения учитывать обязательно стоит.

Не все языки имеют одинаковые грамматики


Принудительное разбиение строк на части

Некоторые разработчики при организации текстовых строк не учитывают грамматику других языков и разбивают текст в строке на несколько значений. В итоге, текстовые сообщения собираются из нескольких кусочков по правилам русского синтаксиса (или родного языка разработчика). Если в переводе на английский ещё и можно как-нибудь выкрутиться (что тоже нечасто удаётся), то, например, в немецком с его жёсткими правилами насчёт порядка слов, при сборке фрагментов в единое предложение получается полный бред. Ну а в арабском, где вообще всё пишется в другую сторону, такой вариант организации контента вообще неприемлем.

Довольно распространённый пример. Русскоязычный пользователь видит сообщение: «До окончания тестового периода осталось 5 дней. Пожалуйста, введите действительный ключ.». В ресурсах это сообщение выглядит следующим образом:

'trialexpires_1': "До окончания тестового периода "
'trialexpires_2sg': "остался "
'trialexpires_2pl': "осталось "
'trialexpires_4sg': " день."
'trialexpires_4pl2': " дня."
'trialexpires_4pl3': " дней."
'enterkey': "Пожалуйста, введите действительный ключ."


В принципе, можно изловчиться и перевести эти «лоскутки» текста на английский язык так, что перевод будет довольно корректным. С арабским языком, где направление текста другое, такой фокус не пройдёт. В немецком языке то и дело отделяемые приставки глаголов норовят убежать в конец предложения. Кстати, ещё раз сравните длительность этой фразы на разных языка — немецкий вариант на 30 % длиннее английского. Жирным шрифтом выделены глаголы. Как вы видите, в немецком языке они могут состоять из двух частей, одна из которых может находиться довольно далеко от другой.

en: Your trial period expires in 5 days. Please enter the valid key.
de: Ihre Testversion läuft in 5 Tagen ab. Bitte geben sie einen gültigen Produktschlüssel ein.

Другим недостатком является то, что при таком представлении переводчик не всегда может уловить логику предложения и добавить корректный перевод. Представьте, как легко можно запутаться в таких кусочках строк, когда их тысяч эдак 5.
Всё это говорит нам о том, что по возможности следует выводить в ресурсы всю строку, чтобы она не только имела наиболее универсальный формат, но и была понятной человеку, который будет её переводить.
Решение для описанной ситуации было бы следующее:

'trialexpires': "До окончания тестового периода [count:остался|осталось] {%n} [count:день|дня|дней]."
'enterkey': "Пожалуйста, введите действительный ключ."


Оператор count (или как бы вы его ни назвали) подставляет нужное текстовое значение в зависимости от числовой переменной %n. При таком представлении проблем не будет и у арабского переводчика, пишущего справа налево — он просто переставит переменные местами.

Вёрстка с помощью принудительного разрыва строки

Довольно частой проблемой является стремление разработчиков обеспечить нужное представление текста в интерфейсе с помощью принудительного разрыва строки. Сразу же приведу пример.
Пользователь видит текст вот так:

Этот текст такой большой,
а окно такое маленькое,
что мне придётся разбить
его по строкам.


В ресурсах это может выглядеть вот так:

'menubox_string1': "Этот текст такой большой,"
'menubox_string2': "а окно такое маленькое,"
'menubox_string3': "что мне придётся разбить"
'menubox_string4': "его по строкам."


На перевод такого безобразия переводчик потратит в несколько раз больше времени, думая, как адаптировать это под свой собственный язык. Если текст будет длиннее (немецкий или французский языки), то четырёх строчек может не хватить. Если текст будет короче (японский или китайский), то пара строк останется пустой. Не говоря уже о том, что если используется технология автоматизированного перевода (при которой перевод каждой строки добавляется в память переводов и используется в аналогичных или похожих строках повторно), то такое разбиение не поможет сделать локализацию эффективной.
Выхода здесь может быть два: либо использовать автоматическую подгонку текста под размеры окна; либо, если доверять переносы машине не хочется, использовать \n.
Тогда текст в ресурсах будет выглядеть так:

'menubox': "Этот текст такой большой,\nа окно такое маленькое,\nчто мне придётся разбить\nего по строкам."


В таком случае перенос строки будет более гибким. Например, переводчику можно сообщить максимальное количество символов в строке и попросить расставить переносы наиболее логично.

Избыточная оптимизация

Эту ошибку допускают слишком старательные контент-менеджеры. Особенно те, кто оптимизирует англоязычные тексты. В излишне оптимизированных ресурсах всё, что только можно (все ключевые слова, а порой и выражения) заменены на постоянные, которые при локализации могут подставляться без учёта падежа, артиклей и прочих особенностей грамматической системы языка перевода. Разумеется, это позволяет лучше контролировать последовательность использования терминологии, а также может существенно снизить расходы на перевод. Но любая оптимизация должна быть разумной. Давайте рассмотрим пример:

Пользователь видит следующий текст:
You can launch the application from the terminal. Press F2 to access the terminal.

В ресурсах он собирается из следующих кусочков:

'cmd': "the terminal"
'app': "the application"
'act_42': "Press F2"
'run_from_terminal': "You can launch {app} from {cmd}. {act_42} to access {cmd}."


Предположим, в интерфейсе много раз используется слова и фразы, которые контент-менеджер заменил на постоянные. Эти постоянные он использует в текстах, т.к. это удобно. Если однажды будет решено, что слово «terminal» неприемлемо, и нужно использовать «command line», либо терминал в системе заменят на, скажем, меню, то не нужно будет обрабатывать огромный массив текста. Достаточно будет просто заменить значение постоянной. Дополнительным плюсом будет снижение общего количества слов. Ведь стоимость перевода чаще всего рассчитывается по количеству слов (значительно реже по количеству строк), а значит общие затраты на локализацию можно будет снизить. Но не тут-то было. Помните, я уже писал, что не все языки работают по одним и тем же грамматическим правилам? Здесь это тоже очень важно.

Давайте посмотрим, как ресурсы в таком виде будут переведены на русский язык.

'cmd': "терминал"
'app': "приложение"
'act_42': "Нажмите F2"
'run_from_terminal': "Вы можете запустить {app} из {cmd}. {act_42} для открытия {cmd}."


Пользователь увидит следующее:

«Вы можете запустить приложение из терминал. Нажмите F2 для открытия терминал».

Если заменить слово «приложение» на слово «программа», то станет ещё хуже, но нагляднее:

«Вы можете запустить программа из терминал. Нажмите F2 для открытия терминал».

Очевидно, что категория падежа в таком подходе не учитывается.
За подобными примерами далеко ходить не надо. Достаточно посмотреть на отвратительно локализованный Foursquare:

Или, взгляните на названия фильтров. Не все из них являются продолжением фразы «Показать места…». Вероятно, это константы, используемые и в других местах. Ну, или просто бездумный перевод и отсутствие тестирования локализации.


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

В русской версии всё-таки лучше будет написать «Место учёбы: %ВУЗ%».
Аналогичный пример из другого раздела:


Вывод: использование текстовых констант, несомненно, полезно, но они должны учитывать другие грамматики. Идеальный подход: использовать числовые постоянные, постоянные единиц измерения (с учётом грамматических особенностей для каждого языка, например, в русском языке 2 множественных числа: 1 уровень, 2 уровня, 5 уровней), имена собственные (названия программных продуктов), сочетания клавиш.

Заключение


Традиционно локализация ПО была отделена от разработки, более того, многие продакт-менеджеры представляют себе локализацию как просто замену оригинального текста иностранным. В результате этого страдает продукт в целом, так как:
  • неоптимизированные ресурсы увеличивают трудозатраты на локализацию;
  • баги, выявленные в процессе локализации увеличивают время выхода продукта на рынок и опять же увеличивают трудозатраты на их устранение;
  • бюджет на локализацию постоянно растёт;
  • «кривая» локализация влияет на количество покупок/загрузок приложения в том или ином регионе и даёт конкурентам лишний шанс. Лично моё мнение – плохо локализованный продукт гораздо хуже вообще нелокализованного.


Даже если приложение написано для локального рынка, то и в этом случае локализация может быть необходима. Вполне возможно, что через пару лет в Москве будет большая потребность в «Яндекс.Картах» на таджикском языке.
Старайтесь разрабатывать приложения с учётом интернационализации и взаимодействуйте с вашим менеджером по локализации или переводческим агентством уже на этапе разработки, чтобы сэкономить себе время, ресурсы и деньги, а также обеспечить максимально высокое качество локальных версий ваших продуктов.
Павел Доронин @scalywhale
карма
36,5
рейтинг 0,0
Специалист по локализации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (66)

  • +1
    Хороший текст, о некоторых языках (и их особенностях даже не задумывался).
    У меня только один вопрос, что написано на бумажке, на первой фотографии.
    • +10
      Спасибо!
      Это кадр из фильма «Евротур», это бумажка с кодовым словом для остановки секс-пытки, которую дали одному из героев. На самом деле надпись на ней ничего не значит, это просто набор символов.
      • 0
        Адское стоп-слово.
        • +2
          fluggaenkdechioebolsen
          • +5
            «FLŰGGÅƏNK∂€ČHIŒβØL∫ÊN» если уж быть точным
      • +2
        «Ханс, Грубер!»
    • +15
      • +14
        Те, кто смотрел фильм, вероятно, побоятся ввести эту капчу.
  • 0
    Как раз размышлял над локализацией нового проекта. Спасибо.
  • +6
    Статья очень нужная, спасибо.
    Отдельное спасибо за ссылку. Печаль в том, что в России и в Украине многие сами не знают собственных норм написания знаков валют и чисел, либо не подозревают о существовании таких норм. Я пару раз указывал на ошибку в русских текстах типа «… получили $ 5,100.00 прибыли», включая крупные новостные ресурсы. Ответ поражает: «Валюта американская, значит правила написания американские», либо «В оригинале вот-так, значит и в переводе должно быть так».
    • 0
      Да, Вы правы, проблема непонятности современных норм нет. Дело в том, что система ГОСТов довольно размыта, очень сложно с ходу найти нужные правила оформления. Как правило, переводческие агентства (а также отделы переводов в больших компаниях) имеют свои внутренние руководства по оформлению чисел, пунктуации и т. д.
      Я всё чаще и чаще замечаю, как русскоязычные люди начинают писать по правилам английского языка. Самый яркий пример — написание заголовков и ключевых слов с заглавной буквы, как в английском языке.
      Скажем, «Мир Одежды и Обуви» — тут можно подумать, что Одежда и Обувь являются женскими именами. Иначе, зачем бы их писать с заглавной?
      И когда всё это переносится на создателей контента, то такое небрежное отношение к языку становится ещё одной проблемой для локализации. В моей практике было немало случаев, когда переводчик присылал перевод, во всех смыслах адекватный оригиналу, включая небрежный стиль. Затем это уже становится головной болью редактора, который шлифует текст до бриллианта, попутно исправляя ошибки не только переводчика, но и того, кто писал исходный текст.
    • 0
      Прошу прощения, выше хотел написать, что проблема непонятности современных форм существует (в русском языке).
  • +4
    Для себя выделяю следующие ключевые особенности:

    1. Локализация — дорогая процедура для внедрения «поверх». Она должна быть заложена в ядре с самого начала.
    2. Ресурсы локализации должны быть независимыми от приложения.
    3. Если в строки подставляются значения, то должны быть локализированы не просто тексты, а сами шаблоны.
    4. При локализации вредно повторное использование элементов. Например, «Сохранить» (файл) и «Сохранить»(настройки) в некоторых языках могут иметь разные названия. Т.е. каждой строке — свой отдельный ресурс, даже если в текущем языке это одна и та же строка. И да, переводить нужно исключительно фразы/предложения целиком.
    5. Локализация распространяется не только на строки. И это так же должно быть учтено при проектировании.
    • 0
      Спасибо! Отличное дополнение и верные выводы. Основная суть именно в этом.
  • 0
    Когда вы упомянули о языках, где текст пишется справа налево, возник такой вопрос: а не должно ли это относиться ко всем элементам интерфейса? Например, для европейской локали кнопочки на тулбаре сгруппированы слева (справа — свободное место), а для арабской — наоборот.
    • 0
      В гайдлайнах по локализации MSDN именно так и предлагают делать. Т.е. локализируется интерфейс целиком.
    • +1
      Расположение — понятно. А порядок следования элементов тоже стоит менять на обратный?
      [да], [нет], [может быть] --> [может быть], [нет], [да]
      • 0
        конечно, он же тоже читается как текст
    • +3
      Да, как правило, ко всем.
      Посмотрите, например, на интерфейс арабского Adobe Acrobat:

      Пункты меню и иконки в нём, а также иконки на панели инструментов расположены слева направо.
      • 0
        Наверняка даже стрелки кнопок «назад» и «вперёд» местами поменяли
  • +2
    Можно еще упомянуть о других календарях и цифрах в некоторых странах
    • 0
      Да, Вы правы, есть разница в представлении даты и времени.
      Самый известный, наверное, пример: в России используется форма даты ДД.ММ.ГГГГ, а в Великобритании — ММ.ДД.ГГГГ.
      Время может быть представлено как в 24-часовом формате (02:00), так и в 12-часовом (2:00 AM). На Тайване (традиционное китайское письмо), насколько я знаю, иероглифы, описывающие время суток, ставятся перед временем (上午 2:00).
      А в промышленном программном обеспечении чаще всего используется универсальное время по стандарту ISO 8601.
      • 0
        Имел в виду не формат даты а то, что не все страны живут по григорианскому календарю.
  • 0
    А я совсем недавно работал примерно над этим механизмом.

    std::cout << Printf("{1|Q=Остался ? день,Остались ? дня,Осталось ? дней}")(nDays);
    std::cout << Printf("Всего {1|q=файл:а,ов}")(nDays);

    Для UTF-16 есть аналогичный класс Wprintf. Механизм почти готов, остаётся придумать т.н. «редкие формы». Например, в русском языке есть четыре формы множественного числа: «один», «мало», «много» и «дробь». Форма «дробь» обычно совпадает с формой «мало», но есть редкие случаи, когда нет. Заодно сокращённая форма — «ворон:а,ы,» — не будет работать (даже на целых числах!), если заявить, что в языке четыре формы множественного числа, придётся писать «ворон:а,ы,,ы».
    • 0
      …Не будет работать из-за «сокращения сокращения» — «файл:а,ов». Особенно эта «двойная сокращённая форма» помогает в английском — «file:s».
    • +2
      Пожалуйста, приведите пример, когда формы «дробь» и «мало» не совпадают. А то я уже измучился, пытаясь подобрать, работа стоит…
      • +1
        Куплен 1 рулон
        Куплены 2 рулона
        Куплено 5 рулонов
        Куплено 1,4 рулона

        В общем, в хитрых случаях, когда единица измерения — это штука, но штука делимая.
      • +2
        Ещё нашёл с разным ударением. Так что, если в строке есть хинты для синтезатора речи, вот пример.

        1 час
        2 часа́
        5 часов
        1,4 ча́са
        • 0
          1,4 часа — на самом деле просто другой падеж. «Одна целая, четыре десятых часа» — родительный. А в остальных вариантах — именительный.
          • +1
            Не совсем. 1,4 часа — это фиксированный родительный падеж единственного числа. 2 часа — согласованное по падежу множественное число. А значит…

            1 метром
            2 метрами
            5 метрами
            1,4 метра
      • 0
        Сам считал, что их три штуки. Но таблица с unicode.org твeрдит: их всё-таки четыре. Долго искал, пока не нашёл.

        А в арабском и валлийском таких форм шесть. Думаю, в этой шестёрке тоже пара форм — редкие.
    • 0
      Помимо закрытых «велосипедов» есть ещё открытый и весьма распространённый gettext.
      Там в конкретных языковых ресурсах прописывается один или несколько регэкспов — и затем уже прописываются для них соответствующие падежные вариации.
      И так можно по вкусу сделать всё вплоть до обзывания однозначных чисел числительными, а двузначных и более — цифрами с соответствующим падежом.
      Никаких изменений в код самой программы при этом не требуется — gettext отлично работает поверх.
  • +1
    принесите флюгегехайнер!!!
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    А вы случайно не подскажете опенсоурсные веб ориентированные системы которым работают с данными где cтроки имеют id?
    Нашел только системы которые работают с форматами без id.
    • 0
      Типа такого? Конечно, имеется в виду не столько Translatewiki, сколько Extension:Translate. Заодно это будет удобная система перевода документации не выходя из вики.

      Ну и Transifex, конечно. Его чуть сложнее установить на свой сервер, но для крупных проектов это просто нечто!
      • 0
        Интересуют именно системы которые поддерживают resource id (когда у каждой строки на перевод есть свой id) — первая судя по всему этого не поддерживает

        Transifex — копаюсь в документации

        • 0
          Нет, Extension:Translate поддерживает.
          Key-based formats: each message has a key, usually a more-or-less meaningful string. Translation to every language is a map of keys pointing to values. Most formats fall into this group, including DTD, JSON, and MediaWiki's own format (essentially a PHP array).
    • 0
      К сожалению, нет. Но, когда у меня возникла необходимость, я сам написал фильтры для таких данных с помощью регулярных выражений в привычной себе переводческой среде Kilgray memoQ. Слышал, что возможность создания подобных фильтров есть в SDL Trados Studio 2011, но пока не пробовал. После фильтрования данные (как правило, JSON или YAML, ещё баловался с ресурсами LUA) преобразовывались в XLIFF и отправлялись на перевод. На выходе я получал те же файлы данных с id с тем же синтаксисом, но уже с переведённым текстом. В зависимости от движка приложения иногда языковые идентификаторы приходилось править руками на нужные.
      Описанные выше решения, к сожалению, не опенсорсные.
  • +4
    Отличная статья! Всё очень знакомо.

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

    Также хорошо бы иметь варианты фраз для единственного числа и множественного: «У вас одно сообщение» лучше «У вас 1 сообщение», в некоторых языках гораздо лучше.
    • 0
      Согласен!
      При локализации социальных приложений мы забирали у сети переменную пола пользователя и использовали соответствующую подстановку:
      {name} [gender:установил|установила] игру «Адское крошилово» и уже [gender:убил|убила] %n зомби!
      

      Про пример с сообщением согласен. Числительные более «душевно» выглядят, чем числа. Если, конечно, число не больше, скажем, 20.
      • 0
        Такая подстановка не очень хороша, потому что позволяет менять только отдельные слова. Потому я и говорю о фразах, чтобы переводчик мог работать со всем предложением. Там всякие артикли, глаголы, может ещё что-то, чего не знаю.
      • 0
        В моей системе это выглядело бы

        Printf("{1} установил{2|0=|1=а} игру «Адское крошилово» и уже убил{2|0=|1=а} {3|q=монстр:а,ов}")
               (name).enu(gender)(nMonsters)
        


        Кстати, идея: придумать команду специально для пола.
        • 0
          Жаль только, ради простоты и производительности невозможно делать подстановку в подстановке. Поэтому одним оператором невозможно реализовать фразы:

          «Лена установила игру „Адское крошилово“, но ещё не убила ни одного монстра»
          «Лена установила игру „Адское крошилово“ и уже убила 10 монстров»
  • +3
    Моё любимое слово для тестирования возможностей системы: Iñtërnâtiônàlizætiøn
  • 0
    А упомянутые популярные XLIFF и .po-файлы все запрошенные фичи поддерживают?
    • 0
      Да. Стоит оговориться, что сами эти форматы ничего не поддерживают, они служат для обмена локализуемыми данными. Грубо говоря, они могут содержать любой текст, который поддерживает Ваш код.
      • 0
        Ок, спрошу иначе, раз Вы так настаиваете. Эти форматы поддерживаются вполне ограниченным перечнем готовых библиотек. Поддерживаются ли всё запрошенные фичи этими библиотеками «из коробки», или их доточить придётся?
        • +1
          Я в разработке не силён, но в тех проектах, которыми я занимался, отделу разработки приходилось «допиливать» библиотеки под собственные нужды. Видимо, всё зависит от особенностей контента в каждом проекте.
  • 0
    Хотелось бы ещё отметить, что в некоторых системах есть хелперы для локализации дат, времён. Однако, они часто могут создавать проблемы, потому что часто нужных форматов нет, и их всё еще приходится собирать «руками».
  • 0
    Добавлю свои пять копеек. В свое время возились с локализацией и версткой, самый ужас в смысле разлапистых слов — новогреческий.
    пароль(рус)
    password(англ)
    Kennwort(нем)
    contraseña(исп)
    κωδικού πρόσβασης(греч)
    • 0
      С новогреческим, кстати, не приходилось сталкиваться. Спасибо за пример, теперь буду знать, чего ожидать!
      • 0
        С греческим сталкивалась ещё с тем, что при необходимости проверить переводчика иногда сложно разобраться, есть у них там вообще в греческом такое слово или нет. В частности, искала слово bit — и в той же википедии оно было то латиницей, то греческим, поди разберись. Больше проблема подбора персонала, но всё же…
  • 0
    Перед стартом нового проекта тоже задумал сразу же писать с учетом интернационализации.
    Добавлю еще к статье алгоритм определения языка интерфейса, к которому я в итоге пришел.
    В порядке приоритета (если нет информации по текущему пункту, берем следующий):
    1) из параметра url,
    2) из cookie,
    3) из страны пользователя, определенной с помощью geo-ip,
    4) из языка браузера пользователя, если он не английский,
    5) язык по умолчанию;
    + возможность сменить язык в панели интерфейса, записав в cookie, т.е. в п.2
    • 0
      В Drupal «из коробки» практически полностью можно реализовать Ваш алгоритм.
      • 0
        Алгоритм именно таков? Подозреваю есть нюансы, можете поделиться?
        • +1
          Доступны следующие методы определения языка:

          1. Определение языка на основе URL (домена или префикса).
          2. Определение языка на основе параметра запроса/сессии.
          3. Следовать языковым предпочтениям пользователя (у каждого пользователя язык по умолчанию может быть разным).
          4. Определение языка на основе настроек языка в браузере.
          5. Использовать язык сайта по умолчанию.

          Приоритет каждого из методов можно менять в произвольном порядке. Также при смене языка обычно меняется URL и cookie.
          • 0
            Ну впринципе тоже самое, спасибо.
  • +2
    Во французском языке вопросительный знак отделяется пробелом
    Интересно, что в канадском французском это не так. По официальным правилам такие знаки не отделяются пробелами спереди. Так что даже, казалось бы, для одного и того же языка есть региональные отличия, и не только в пунктуации.
    • 0
      Интересное замечание, спасибо! Интересно также заметить, что из этих же официальных правил видно, что кавычки в Канаде также отбиваются пробелами с двух сторон, как и во Франции. Теперь мне любопытно, почему же отличаются правила по поводу вопросительного знака?..
      • 0
        Скорее всего, просто сложившееся региональное изменение традиции. Ну то есть, ничем разумным это не объясняется :-)
        Сами канадцы говорят про их английский, что британцы при встрече с канадским английским принимают его за американский, американцы — за британский. На самом же деле, он отличается от обоих.
      • 0
        Скорее всего сказалось влияние английского языка.
  • 0
    Еще один немаловажный пункт локализации — направление написания. Как правило стараются поддерживать два основных LTR (left-to-right), RTL (right-to-left) для азиатских языков, ну а в таких экзотических странах как Монголия где используется TTB (top-to-bottom) о Интернете и компьютере мало кто слышал и слава богу для разработчиков в серьезе озадачившихся локализацией.
  • +1
    Я столкнулся с проблемой, когда нужно поставить в правильном падеже слово, которое идёт в качестве параметра. Вот например,
    System.out.format("The message was sent to %s %s", user.getName(), user.getSurname()); System.out.format("Сообщение было отправлено %s %s", user.getName(), user.getSurname());
    Иными словами, если в английском имя не меняется, то в русском имя желательно поставить в Дательный падеж (в данном случае). Как самое быстрое решение можно вставить слово «пользователю». Получится вместо «сообщние отправлено Вася Пупкин» что-то типа «сообщение отправлено пользователю Вася Пупкин». Немного коряво, но позволяет обойтись малой кровью. Я пока ещё не нашёл единого верного решения, как справиться с этой задачей наиболее оптимальным путём.
    • 0
      Думаю, что в таком случае придётся создавать массив с различными словоформами, релевантными для конкретного языка, а затем подставлять их в текст. В разных языках глаголы могут управлять разными формами существительных.
      А вот с именами, наверное, будет сложнее. Если кто-то помнит, в 2007 году ВКонтакте очень часто ошибался со склонением имён и фамилий пользователей. Те, кто замечал, что их имя стоит в неверном падеже, могли сообщить об этом в техподдержку. Вероятнее всего, таким образом «прокачивался» их движок склонения.
      Думаю, что каким-то образом у имени распознавалась основа, к которой подставлялось нужное окончание в зависимости от пола пользователя и предыдущих букв. Например, в дательном падеже имена мужского рода получают «у» или «ю», в зависимости от того, обозначает предыдущая буква мягкий звук или твёрдый.
      Игорь → Игорю
      Александр → Александру
      Имена-исключения из правил проще всего собрать по отзывам пользователей. Имена, написанные латиницей, исключаются из склонения.
      Вообще, с именами задача очень интересная, думаю о ней уже несколько дней :)
  • 0
    Спасибо, хороший текст :)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.