Oct 29 2008

Symfony: интернационализация (I18n) / часть 1 — введение

Category: Symfonyingvar @ 00:32

Начинаю цикл статей по организации мультиязычности в Symfony. Мультиязычность достигается с помощью интернационализации и локализации.

Часть 1.1: интернационализация (I18n) — введение

Немного теории (источник Википедия).

Интернационализа́ция (англ. internationalization) — процесс адаптации продукта, такого как программное или аппаратное обеспечение, к языковым и культурным особенностям региона (регионов), отличного от того, в котором разрабатывался продукт. В английском языке для слова «internationalization» принято сокращение «i18n». При этом число 18 означает количество пропущенных между «i» и «n» букв.

Локализа́ция (англ. localization) — перевод и адаптация элементов интерфейса, вспомогательных файлов и документации. В английском языке для слова «localization» иногда применяется сокращение «l10n». При этом число 10 означает количество пропущенных между «l» и «n» букв.

Собственно хорошая поддержка интернационализации в Symfony на фоне других систем, а также многие другие возможности помогли мне остановиться на этом замечательном фреймворке :).

Хочу поделиться моим небольшим опытом и достигнутыми результатами упрощения организации работы с I18n в Symfony. Весь материал разбил на несколько частей.

Использовалась Symfony 1.1 и Propel 1.3.

Мои требования к интернационализации (I18n) для фреймворка:
1) Локализация интерфейса сайта
2) Интернационализации данных (новости, статьи, продукция,…)
3) Административная панель: редактирование локализации интерфейса
4) Административная панель: редактирование данных с учетом интернационализации
5) Простота использования, гибкость (возможность легко добавить новый язык), производительность
6) Работать с локализацией через БД (MySQL), в частности через PDO (Propel 1.3), используя открытый коннект к БД

Symfony практически «справляется» со всеми требованиями. Но для некоторых процессов пришлось кое-что изменить, доработать. Добился ли я выполнения поставленных задач? ДА!!!!!

По умолчанию доступен один язык, и его можно активировать через настройки: frontend/config/settings.yml

Листинг 1.1: настройка «культуры» по умолчанию

all:
  .settings:
    default_culture: ru_RU  # или uk_UA

Не забудьте сбросить кеш.

Формат записи (локали): uk_UA — язык и код страны.

Таким образом, мы говорим, какой профиль использовать для интернационализации.
Список всех профилей можно найти в ядре Symfony: /symfony-1.1/lib/i18n/data/

Теперь если использовать Helpers, которые работают с I18n (календарь, список стран, дата…) мы на выходе получим тексты не в английском языке по умолчанию, а в украинском.

Листинг 1.2: получение текущей «культуры»

$culture = $this->getUser()->getCulture();

 

Часть 1.2: организация итернационализации (I18n) контента в Symfony

Сначала расскажу, как организована интернационализация данных, а после вернемся к локализации интерфейса в других частях.

Вначале наши данные без поддержки I18n имеют следующий вид.

Листинг 1.3: схема таблицы «Статьи» (schema.yml)

propel:
  _attributes:          { package: lib.model.article }

  article:
    id:                 ~
    slug:               { type: varchar, size: 255, required: true }
    image_url:          { type: varchar, size: 255, required: true }
    title:              { type: varchar, size: 255, required: true }
    announce:           { type: text, required: true }
    full_text:          { type: text, required: true }
    created_at:         ~

Листинг 1.4: Маршрутизация (routing.yml):

article:
  url: /articles/:year/:month/:day/:slug
  param: { module: article, action: index }

Ссылка на статью имела бы следующий вид: http://tigor.com.ua/articles/2008/10/28/i18n_hello_world

Добавляем интернационализацию.

Листинг 1.4: Маршрутизация с поддержкой I18n (routing.yml)

article:
  url: /:sf_culture/articles/:year/:month/:day/:slug
  param: { module: article, action: index }
  requirements: { sf_culture: (?:ru|uk|en) }

Указываем к примеру 3-и языка: русский, украинский, английский. Если ввести что-то другое вместо языка, то страница будет не найдена, и получим код ошибки 404.

Теперь ссылка будет вот такая:
• http://tigor.com.ua/en/articles/2008/10/28/i18n_hello_world
• http://tigor.com.ua/ru/articles/2008/10/28/i18n_hello_world
• http://tigor.com.ua/uk/articles/2008/10/28/i18n_hello_world

Но контент все еще на одном языке. Делаем правки схемы.

Листинг 1.5: схема с поддержкой I18n (schema.yml)

propel:
  _attributes:          { package: lib.model.article }

  article:
    _attributes:        { phpName: Product, isI18N: true, i18nTable: article _i18n }
    id:                 ~
    slug:               { type: varchar, size: 255, required: true }
    image_url:          { type: varchar, size: 255, required: true }
    created_at:         ~

  article _i18n:
    id:                 { type: integer, required: true, primaryKey: true, foreignTable: article,
       foreignReference: id, onDelete: cascade, onUpdate: cascade }
    culture:            { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
    title:              { type: varchar, size: 255, required: true }
    announce:           { type: text, required: true }
    full_text:          { type: text, required: true }

В Листинге 1.5 для таблицы article _i18n сознательно указаны id и culture, чтобы отобразить, что же Symfony вставляет при указании опции isI18N. Эти поля указывать не стоит, дабы не совершать ошибки. Но в исключительных это может понадобиться.

Листинг 1.6: Небольшие примеры работы с объектом Article

// Чтение данных
$article = ProductPeer::retrieveByPk(1);
$title = $article ->getTitle(); // По умолчанию испольщуется текущая культура, или переопределенная через машрутизацию
$title = $article ->getTitle(‘en’); // Явно указываем язык

// Изменение данных
$article = ProductPeer::retrieveByPk(1);
$article->setTitle(‘Мир во всем мире!’, ‘ru’);
$article->save();

Ссылки по теме:
Symfony: интернационализация (I18n) / часть 2 – редактирование данных в административной панели
Википедия: Интернационализация
Википедия: Локализация
Wikipedia: Internationalization_and_localization
The Definitive Guide to symfony: Chapter 13 — I18n And L10n

Tags: ,

9 Responses to “Symfony: интернационализация (I18n) / часть 1 — введение”

  1. Дармен Аманбаев says:

    Большое спасибо за статью!

    Игорь, скажите — у Вас был опыт локализации интерфейса, генерируемого «Admin Generator», который поставляется с Symfony?

    То есть кнопки вида «Edit», «Delete», «Create», надписи об успешном добавлении/изменении и т.п.

    Дело в том, что мне не удалось, даже при указанной «культуре» в настройках, локализовать его.

  2. Snowcore says:

    Мне тоже очень нравится подход, который используется в Symfony для поддержки мультиязычности. Все просто и удобно.

  3. ingvar says:

    Re: Дармен Аманбаев
    Да это можно сделать. Все тексты в админке выводяться через функцию локализации __($name). В этом случае надо локализировать админку как и сам сайт. Некоторые тексты можно задать через файлы generator.yml, остальное только через локализацию (i18n).

  4. igor says:

    у меня стоит сандбокс 1.1 я создал схему по этому примеру прописал настройки все как по примеру только заменил их на ru. но по какой-то причине в админке язык на русский не переводится при экшене лист. вопрос как сделать админку всю на русском. и как сделать переключение между языками в админке

  5. ingvar says:

    2Igor: Чтобы админку перевести на русский язык, надо:
    1) Сделать локализацию для неё
    2) Использовать русские фразы в generator.yml
    Переключение можно сделать так, к примеру через параметр /admin/?lang=ru -а в контролере менять культуру, или так /admin/ru/

  6. Виктор says:

    В документации написанно что словари (в случае использования XLIFF) могут находиться в директориях модулей.

    http://www.symfony-project.org/book/1_1/13-I18n-and-L10n
    Another way to organize translation dictionaries is to split them by module. Instead of writing a single messages.XX.xml file for the whole application, you can write one in each modules/[module_name]/i18n/ directory. It makes modules more independent from the application, which is necessary if you want to reuse them, such as in plug-ins (see Chapter 17).

    У меня не получаеться заставить его работать таким образом. Я что-то упустил?

  7. ingvar says:

    У меня тоже не получилось этого сделать. Папка i18n находиться в самом apps. Как вариант можно создавать отдельный файлы для модулей и вызывать < ?php echo __('Welcome to our website', null, 'navigation') ?>: navigation — этот самый файл.

  8. Виктор says:

    Понятно. Я так и сделал уже… Потом поробую разобраться, может получиться все-таки в папку с модулем закинуть словарь

Leave a Reply to Виктор