Книга: Программирование на языке Ruby
4.3.3. Локализация простого приложения
4.3.3. Локализация простого приложения
В следующем примере определяется класс Person, после чего с ним выполняются различные действия. Метод show выводит локализованные сообщения:
require 'gettext'
class Person
include GetText
def initialize(name, age, children_num)
@name, @age, @children_num = name, age, children_num
bindtextdomain("myapp")
end
def show
puts _("Information")
puts _("Name: %{name}, Age: %{age}") % {:name => @name, :age => @age}
puts n_("%{name} has a child.", "%{name} has %{num} children.",
@children_num) % {:name => @name, :num => @children_num}
end
end
john = Person.new("John", 25, 1)
john.show
linda = Person.new("Linda", 30, 3)
linda.show
Предположим, что этот код сохранен в файле myapp/person.rb
. Как вы скоро увидите, иерархия каталогов имеет значение. Вызов метода bindtextdomain
связывает текстовый домен "myapp"
с объектом Person
во время выполнения.
В методе show
есть три обращения к библиотеке gettext
. Вызываемый метод называется _
(одно подчеркивание), чтобы не отвлекать внимание.
Первое обращение просто выводит локализованное сообщение, соответствующее строке "Information"
. Второе демонстрирует локализованное сообщение с двумя параметрами. В хэше задается список значений, подставляемых в строку. Интерполировать их напрямую нельзя, потому что это вступало бы в противоречие с основной целью: хранить в справочнике небольшое число сообщений.
Отметим также, что параметры отделены от текста сообщения, поэтому при необходимости могут подставляться в другом порядке. Ведь иногда при переводе на другой язык приходится переставлять слова.
Тот же метод можно вызвать и короче:
puts _("Name: %s, Age: %d") % [@name, @age]
Однако мы рекомендуем более длинную запись. Она понятнее и дает больше информации переводчику.
Метод n_
предназначен для обработки единственного и множественного числа. Значение параметра @children_num
— индекс, говорящий о том, какую из заранее заданных строк использовать. (Правило Plural-Forms
, о котором я скоро расскажу, определяет порядок вычисления индекса.)
Отметим, что сообщения по умолчанию обязаны быть англоязычными (даже если родной язык программиста не английский). Нравится вам это или нет, но английский ближе всего к универсальному языку с точки зрения большинства переводчиков.
Я сказал, что нам пригодится программа rake
. Создадим файл Rakefile
(в каталоге myapp
) для сопровождения справочников сообщений. Он будет выполнять две основные операции: обновлять РО-файлы и создавать МО-файлы.
require 'gettext/utils'
desc "Update pot/po files."
task :updatepo do
GetText.update_pofiles("myapp", ["person.rb"], "myapp 1.0.0")
end
desc "Create mo-files"
task :makemo do
GetText.create_mofiles
end
Здесь мы воспользовались библиотекой gettext/utils
, в которой имеются функции для работы со справочниками сообщения. Метод update_pofiles
создает начальный файл myapp/ро/myapp.pot
на основе исходного текста person.rb
. При втором (и всех последующих) вызовах эта функция выполнит обновление, или слияние файла myapp/po/myapp.pot
и всех файлов вида myapp/po/#{lang}/myapp.ро
. Второй параметр — массив целевых файлов. Обычно он задается примерно так:
GetText.update_pofiles("myapp",
Dir.glob("{lib,bin}/**/*.{rb,rhtml}"),
"myapp 1.0.0")
Вызов метода GetText.create_mofiles
создает необходимые подкаталоги в каталоге data/locale/
и генерирует МО-файлы из РО-файлов.
Итак, выполнив команду rake updatepo
, мы создадим каталог myapp/ро
, а в нем файл myapp.pot
.
Теперь отредактируем заголовок файла po/myapp.pot
. Он содержит описание приложения (название, имя автора, адрес электронной почты, условия лицензирования и т.д.).
# Пример приложения. (Осмысленное название)
# Copyright (С) 2006 Foo Bar (Автор приложения)
# Файл распространяется по лицензии XXX. (Лицензия)
#
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. (Информация о переводчике)
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: myapp 1.0.0n" (ID и версия проекта)
#...
Что такое маркер fuzzy
? Так отмечается тот факт, что какая-то часть не переведена или перевод вызывает сомнения. Все автоматически сгенерированные сообщения помечаются таким образом, чтобы человек знал, что их нужно проверить и изменить.
Файл myapp.pot
нужно разослать переводчикам. (Конечно, вы можете перевести его и самостоятельно.)
Предположим, что вы переводите на японский язык. На машине установлена локаль ja_jp.UTF-8
, что означает «Япония (ja
), японский язык (JP
), кодировка UTF-8».
Для начала скопируем файл myapp.pot
в myapp.ро
. При наличии набора GNU-утилит gettext
лучше воспользоваться командой msginit
, а не просто cp
. Эта утилита учитывает переменные окружения и правильно устанавливает некоторые переменные в заголовке. В UNIX она вызывается следующим образом:
LANG=ja_JP.UTF-8 msginit -i myapp.pot -o myapp.po
Затем отредактируйте файл myapp.ро
, как показано в листинге 4.3. Редактировать необходимо в той кодировке, которая указана в строке Content-Type
.
Листинг 4.3. Файл myapp.ро после редактирования
# Пример приложения.
# Copyright (С) 2006 Foo Bar
# Файл распространяется по лицензии XXX.
#
# Ваше имя <[email protected]>, 2006. (Вся информация о переводчике)
# (Удалите строку 'fuzzy')
msgid ""
msgstr ""
"Project-Id-Version: myapp 1.0.0n"
"POT-Creation-Date: 2006-05-22 23:27+0900n"
"PO-Revision-Date: 2006-05-23 14:39+0900n"
# Информация о текущем переводчике.
"Last-Translator: Your Name <[email protected]>n"
"Language-Team: Japanesen" (Ваш язык)
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n" (Кодировка файла)
"Content-Transfer-Encoding: 8bit r."
# Форма множественного числа.
"Plural-Forms: nplurals=2; plural=(n != l);n"
#: person.rb:12
msgid "Information"
msgstr "Jouhou"
#: person.rb:13
msgid "Name: %{name}, Age: %{age}"
msgstr "Namae: %{name}, Nenrei: %{age}"
#: person.rb:14
msgid "%{name} has a child."
msgid_plural "%{name} has %{num} children."
msgstr[0] "%{name} ha hitori kodomo ga imasu."
msgstr[1] "%{name) ha %{num} nin no kodomo ga imasu."
Тегом msgid
помечается исходное сообщение, а тегом msgstr
— переведенное. При наличии строки msgid_plural
необходимо включить отдельные строки msgstr[i]
в соответствии с правилом Plural-Forms
. Индекс i
вычисляется на основе выражения Plural-Forms
. В данном случае при num != 1
используется msgstr[1]
(сообщение с существительным во множественном числе).
Истоки синтаксиса правила Plural-Forms
следует искать в языке С. Как видим, он опирается на тот факт, что булевские выражения в С возвращают 0 или 1.
Имейте в виду, что формы единственного и множественного числа в большой степени зависят от языка. Во многих языках есть несколько форм множественного числа. Например, в польском слово «файл» в единственном числе записывается как «plik». Если количество экземпляров заканчивается на 2, 3 и 4, то во множественном числе пишется «pliki», а во всех остальных случаях — «plik?w».
Поэтому для польского языка правило Plural-Forms
выглядит так:
Plural-Forms: nplurals=3;
plural=n==1 ? 0 :
n%10>=2 && n%10<=4 && (n%100=20) ? 1 : 2;
Заголовок файла — не пустая формальность. Особенно важны разделы Content-Type
и Plural-Forms
. При пользовании утилитой msginit
они вставляются автоматически, в противном случае необходимо добавить их вручную.
Закончив работу, переводчик посылает файлы обратно разработчику (или вы сами возвращаетесь к роли разработчика).
Файлы myapp.ро
, полученные от переводчиков, помещаются в соответствующие каталоги (внутри каталога myapp/ро
). Например, французскую версию следовало бы поместить в каталог myapp/ро/fr/myapp.ро
, немецкую — в каталог myapp/po/de/myapp.ро
и т.д.
Затем выполните команду rake makemo
. Она преобразует РО-файлы в МО-файлы. Сгенерированные МО-файлы будут помещены в каталог myapp/data/locale/
(в котором есть подкаталоги для каждого языка).
Таким образом, окончательная структура дерева каталогов выглядит так:
myapp/
Rakefile
person.rb
ро/
myapp.pot
de/myapp.po
fr/myapp.po
ja/myapp.po
:
data/
locale/
de/LC_MESSAGES/myapp.mo
fr/LC_MESSAGES/myapp.mo
ja/LC_MESSAGES/myapp.mo
:
Перевод закончен, можно протестировать пример. Но предварительно следует указать, где искать МО-файлы и для какой локали проводится тестирование. Установим переменные окружения GETTEXT_PATH
и LANG
, запустим программу и посмотрим, что она выведет.
export GETTEXT_PATH="data/locale"
export
ruby person.rb
Программа выводит локализованные сообщения в соответствии со значением переменной lang
.
- Глава 13 Интернационализация и локализация
- 1.8 Ввод-вывод типичного приложения хранения данных
- Извлечение и возврат документов в приложениях Microsoft Office 2007
- Использование панели задач Управление документами в приложениях Office 2007
- Приложение E. Локализация
- Каждый раз после загрузки Windows запускаются разные бесполезные приложения, а возле часов появляются лишние значки. Что...
- Удаляю Windows Messenger из автозапуска, но после перезагрузки программа снова запускается. С другими приложениями таког...
- Создание приложения-клиента в C#
- Глава 4 Работа с приложениями
- Управление приложениями
- Пример приложения Pocket PC, демонстрирующий работу средств контроля запуска событий
- Глава 23 Использование команд для доступа к приложениям