Программирование на языке Ruby - Хэл Фултон
Шрифт:
Интервал:
Закладка:
«Наилучший» способ реализовать эту идею в Ruby — воспользоваться библиотекой Ruby-GetText-Package. Я буду называть ее просто gettext, поскольку именно так называется содержащий ее файл (не путайте с утилитой gettext!). Эту великолепную библиотеку написал Macao Муто (Masao Mutoh), он же очень помог при написании данного раздела.
Библиотека представляет собой реализацию на Ruby (не обертку) набора утилит gettext из проекта GNU (самый известный продукт в этой области). Ее официальный сайт находится по адресу http://gettext.rubyforge.org/, а утилиты GNU можно найти на сайте http://www.gnu.org/software/gettext/.
4.3.1 Исторические сведения и терминология
Библиотека gettext на самом деле, как мы увидим, состоит из нескольких библиотек. Для доступа к основным функциям нужно включить предложение require 'gettext', а для получения разного рода дополнительных средств (в частности, работы со справочниками сообщений) — предложение require 'gettext/utils'.
Главная причина, по которой мы используем справочники сообщений, — это, конечно, перевод сообщений на другие языки. С их помощью мы также обрабатываем случаи, когда формы единственного и множественного числа различаются (один файл, два файла). Кстати, эти правила очень сильно зависят от конкретного языка.
Обычно у каждой библиотеки и приложения имеется собственный справочник сообщений. Следовательно, в дистрибутив можно включать набор переведенных на разные языки справочников.
Учитываются переменные окружения LANG и GETTEXT_PATH. Их назначение мы рассмотрим ниже.
Для сопровождения справочника сообщений есть две основных операции (они выполняются вне вашей программы): извлечь сообщения из исходного текста Ruby-программы для формирования начального справочника и включить новые сообщения из исходного текста в существующий справочник (слияние). Операции извлечения и слияния мы рассмотрим в разделе 4.3.3.
4.3.2. Приступаем к работе со справочниками сообщений
Возможно, библиотека gettext на вашем компьютере уже установлена. Если нет, проще всего выполнить команду gem install gettext.
Для разработки вам понадобятся утилиты GNU. Если вы работаете в системе UNIX, то, скорее всего, они уже установлены. В случае платформы Win32 можно установить Glade/GTK+ для Windows; заодно вы получите и утилиты GNU. В любом случае необходимы они только на этапе разработки, а не во время выполнения.
Если у вас нет программы rake, установите ее из gem-пакета. Это дополнительное удобство.
Коль скоро среда настроена и все установлено, можно приступать к работе со справочниками. Но сначала познакомимся с терминологией.
• РО-файл — это переносимый объектный файл. Так называется текстовое (понятное человеку) представление справочника сообщений. У каждого такого файла есть вариант для различных поддерживаемых локалей. РОТ-файл — это шаблон.
• МО-файл — это переносимый двоичный файл справочника. Он создается из РО-файла. Библиотека для Ruby умеет читать только МО-файлы, но не РО-файлы.
• Текстовый домен — это, по существу, просто базовое имя МО-файла. Он ассоциирован с приложением (привязан к нему).
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 protected]>, 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.