Переклади

10/06/2016 0 symfony, налаштування, конфігурація

Термін “інтернаціоналізація” (часто його пишуть у формі абревіатури i18n) відсилає нас до процесу добування рядків тексту та інших, специфічних для конкретної локалі, об’єктів з вашого додадку, і переміщення їх на певний рівень абстракції, де ці елементи можна перевести і конвертувати базуючись на локалі користувача (тобто залежно від мови і країни). Для тексту це означає, що його потрібно передавати у спеціальну функцію, яка здатна перекладати тексти (або прості повідомлення) на мову користувача:  

// text will *always* print out in English
dump('Hello World');
die();

// text can be translated into the end-user's language or
// default to English
dump($translator->trans('Hello World'));
die();

Термін локаль означає сукупність мови і країни користувача. Це може бути будь-який рядок, який ваш додаток зможе використати для того, щоб керувати перекладами, та іншими відмінностями у форматах (наприклад, формат валюти). Рекомендують використовувати стандарт  ISO 639-1 для мовних кодів, підкреслення (_), а потім стандарт ISO 3166-1 alpha-2 кодів країн (наприклад, fr_FR для French/France).

У цьому розділі ви дізнаєтесь, як використовувати компонент перекладу (Translation component) у Symfony. Щоб вивчити ще більше, ви можете прочитати документацію Translation component documentation. Загалом процес складається з декількох стандартних етапів:

  1. Підключити та налашувати сервіс перекладів у Symfony;

  2. Абстрагувати рядки (“повідомлення”) загортаючи їх у виклики до Translator ("Basic Translation");

  3. Створити файли/ресурси перекладу для кожної локалі, яка підтримується і перекладає кожне повідомлення в додадку;

  4. Визначити, встановити та керувати локалем користувача, на запит або вибірково, за допомогою сесії.

Налаштування 

Переклади обробляються сервісом translator, який використовує локаль користувача для пошуку і відображення перекладеного повідомлення. Перш як його використовувати, підключіть  translator у файлі конфігурації.

YAML

# app/config/config.yml
framework:
    translator: { fallbacks: [en] }

XML

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

    <framework:config>
        <framework:translator>
            <framework:fallback>en</framework:fallback>
        </framework:translator>
    </framework:config>
</container>

PHP

// app/config/config.php
$container->loadFromExtension('framework', array(
    'translator' => array('fallbacks' => array('en')),
));

Читаючи цей розділ далі, ви дізнаєтесь деталі про ключ fallbacks, і що робитиме Symfony якщо не знайде перекладу.

Локаль, що використовується для перекладів зберігається в сесії користувача. Зазвичай це налаштовується через властивість _locale у ваших маршрутах.  

Основи перекладів

Переклад тексту втілюється через сервіс translator (Translator). Для перекладу блоку тексту (який називається повідомленням), використайте метод trans(). Наприклад, ви перекладаєте просте повідомлення з середини контролера:

// ...
use Symfony\Component\HttpFoundation\Response;

public function indexAction()
{
    $translated = $this->get('translator')->trans('Symfony is great');

    return new Response($translated);
}

Коли цей код виконуватиметься, Symfony спробує перекласти повідомлення "Symfony is great", беручи за основу локаль користувача. Для цього, необхідно вказати Symfony як перекласи це повідомлення, використовуючи “ресурс для перекладу”, який складається з перекладених повідомлень для потрібної локалі. Цей “словник” перекладів може бути створений у різних форматах, рекомендуємо використати формат XLIFF:

XML
<!-- messages.fr.xlf -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="symfony_is_great">
                <source>Symfony is great</source>
                <target>J'aime Symfony</target>
            </trans-unit>
        </body>
    </file>
</xliff> 

YAML

# messages.fr.yml
Symfony is great: J'aime Symfony

PHP

// messages.fr.php
return array(
    'Symfony is great' => 'J\'aime Symfony',
);

Більше інформації про те, де ці файли повинні знаходитись ви дізнаєтесь пізніше у цьому розділі (підрозділ Ресурс перекладу/Імена та локації файлів).

Тепер, якщо локалем користувача буде французька мова (наприклад, fr_FR або fr_BE), це повідомлення буде перекладене як  “J'aime Symfony”. Також, ви можете перекласти повідомлення у ваших шаблонах. 

Процес перекладу

Щоб перекласти повідомлення, Symfony використовує простий процес, а саме:  

  • Визначає локаль поточного користувача, яка зберігається в сесії;  

  • Завантажує каталог перекладів повідомлень з відповідного ресурсу, який визначається локалем (наприклад, fr_FR). Повідомлення, що відповідають резервній локалі (fallback locale), також завантажуються і додаються до каталогу, якщо він ще не завантажений. Результат -  великий “словник” з перекладами.   

  • Якщо повідомлення є в каталозі, ви отримуєте переклад. Якщо ні - перекладач повертає вам текст мовою оригіналу.   

Якщо ви будете користуватись методом trans(), Symfony шукатиме рядок в підходящому каталозі, і повертатиме його (якщо такий рядок існує).  

Заповнювачі у повідомленнях

Інколи, повідомлення, яке потрібно перекласти містить змінну:

use Symfony\Component\HttpFoundation\Response;

public function indexAction($name)
{
    $translated = $this->get('translator')->trans('Hello '.$name);

    return new Response($translated);
}

Проте, для цього рядка неможливо створити переклад, оскільки перекладач буде шукати ідентичний рядок, разом зі змінною (наприклад, "Hello Ryan" або "Hello Fabien"). 

Детальніше про те, як вийти з цієї ситуації, ви можете прочитати у підрозділі Message Placeholders у документації. Як використовувати цей метод у шаблонах, читайте нижче (Шаблони Twig). 

Плюралізація

Ще одна складність, це коли ви маєте справу з перекладами які можуть або бути, або не бути у множині, базуючись на якій-небудь змінній:

There is one apple.
There are 5 apples.

Щоб справитись з цим завданням, використайте метод transChoice(), або тег/фільтр  transchoice у вашому шаблоні.

Більше про таку річ як плюралізація ви можете прочитати у документації.   

Переклади у шаблонах

Найчастіше, перекладати приходиться саме у шаблонах. Symfony за своєю природою підтримує шаблони Twig і PHP.

Шаблони Twig

Symfony надає спеціальні теги Twig (trans і transchoice), а вони допомагають перекласти повідомлення статичних блоків тексту.  

{% trans %}Hello %name%{% endtrans %}

{% transchoice count %}
    {0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples
{% endtranschoice %}

Тег transchoice автоматично дістає змінну %count% поточного контенту і передає її перекладачеві. Цей механізм працює лише у тому випадку, коли ви використовуєте заповнювачі за зразком %var%.

Запис %var% заповнювачів є необхідністю при перекладі у шаблонах Twig з використанням тега. 

Якщо вам потрібен знак відсотків (%) у рядку, ви можете уникнути його, подвоївши: {% trans %}Percent: %percent%%%{% endtrans %} 

Крім того, можна вказати домен повідомлення і передати деякі додаткові змінні:

{% trans with {'%name%': 'Fabien'} from "app" %}Hello %name%{% endtrans %}

{% trans with {'%name%': 'Fabien'} from "app" into "fr" %}Hello %name%{% endtrans %}

{% transchoice count with {'%name%': 'Fabien'} from "app" %}
    {0} %name%, there are no apples|{1} %name%, there is one apple|]1,Inf[ %name%, there are %count% apples
{% endtranschoice %}

Фільтри trans і transchoice можуть використовуватися для перекладу змінних текстів та складних виразів:

{{ message|trans }}

{{ message|transchoice(5) }}

{{ message|trans({'%name%': 'Fabien'}, "app") }}

{{ message|transchoice(5, {'%name%': 'Fabien'}, 'app') }}

Використання цих тегів або фільтрів для перекладів часто має такий самий ефект, проте є одна незначна відмінність:для перекладів з фільтром потрібно використати автоматичне маскування. Іншими словами, коли вм потрібно переконатися, що перекладене повідомлення не виводиться, вам слід використати фільтр raw після фільтру перекладу:

{# text translated between tags is never escaped #}
{% trans %}
    <h3>foo</h3>
{% endtrans %}

{% set message = '<h3>foo</h3>' %}

{# strings and variables translated via a filter are escaped by default #}
{{ message|trans|raw }}
{{ '<h3>bar</h3>'|trans|raw }}

Ви можете поставити домен перекладів для усього шаблону Twig за топомогою одного тега:

{% trans_default_domain "app" %}

Зверніть увагу, це впливає лише на поточний шаблон, а не на будь-який “включений” шаблон (для того щоб уникнути побічних ефектів).

Шаблони PHP

Сервіс для перекладу доступний у шаблоних PHP через хелпер translator:

<?php echo $view['translator']->trans('Symfony is great') ?>

<?php echo $view['translator']->transChoice(
    '{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples',
    10,
    array('%count%' => 10)
) ?>

Імена і розміщення ресурсів/файлів для перекладу

За замовчуванням Symfony шукає файли з повідомленнями (тобто, переклади) у таких локаціях:

  • директорія app/Resources/translations;

  • директорія app/Resources/<bundle name>/translations;

  • всередині будь-якого пакету Resources/translations/ directory.

Локації перечислені у порядку пріоритетності. Це означає, що ви можете перевизначити повідомлення пакету в будь-якій з двох найкращих директорій.  

Механізм перевизначення працює на такому ключовому рівні: лише перевизначеним ключам потрібно дати вищу пріоритетність у файлі з повідомленнями. Коли пограма не може знайти ключ у файлі з повідомленнями, перекладач автоматично перейде до файлів з повідомленнями меншої пріоритетності.    

Імена файлів з перекладами також відіграють важливу роль. Кожен файл з повідомленням повинен мати ім’я згідно такого шляху: domain.locale.loader:

  • домен (domain): Оптимальний спосіб погрупувати повідомлення (наприклад, admin, navigation або за замовчуванням messages) - читайте підрозділ “Використання доменів повідомлень”;

  • локаль (locale): локалі, для яких є переклади (наприклад: en_GB, en, і т. д);

  • завантажувач (loader): як Symfony повинна завантажувати і інтерпретувати файл  (наприклад: xlf, php, yml, і т. д).

Завантажувач може мати ім’я будь-якого зареєстрованого завантажувача. За замовчуванням Symfony надає багато завантажувачів, включаючи:  

  • xlf: XLIFF файл;

  • php: PHP файл;

  • yml: YAML файл.

Вибір, яким з них користуватися залежить від вашого смаку. Рекомендована опція - xlf для перекладів. Більше опцій у підрозділі “Каталоги завантажування повідомлень”.

Ви можете додати і інші директорії з варіантами шляхів у конфігурацію:  

YAML

# app/config/config.yml
framework:
    translator:
        paths:
            - '%kernel.root_dir%/../translations'

XML

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>

    <framework:config>
        <framework:translator>
            <framework:path>%kernel.root_dir%/../translations</framework:path>
        </framework:translator>
    </framework:config>
</container>

PHP

// app/config/config.php
$container->loadFromExtension('framework', array(
    'translator' => array(
        'paths' => array(
            '%kernel.root_dir%/../translations',
        ),
    ),
));

Ви можете зберігати переклади у базі даних, або будь-якому іншому сховищі, створивши користувацький клас з інтерфейсом LoaderInterface. більше інформації про це знайдете у документації Symfony: translation.loader.


Кожного разу. коли ви створюєте новий росурс перекладів (або встановлюєте пакет, що включає ресурс перекладів), переконайтесь, що ви почистили кеш, тоді Symfony зможе знйти нові ресурси для перекладів:

php bin/console cache:clear

Резервні локалі перекладу

Уявімо, що   fr_FR - локаль користувача, і що ви перекладаєте фразу Symfony is great. Щоб знайти французьий переклад, Symfony фактично перевіряє ресурси перекладу на декілька локалей:  

  1. Спочатку Symfony шукатиме цей переклад у ресурсі fr_FR (наприклад, messages.fr_FR.xlf);

  2. Якщо фреймворк нічого не знайде, тоді Symfony шукатиме це у ресурсі  fr  (наприклад, messages.fr.xlf);

  3. Якщо переклад все ще не буде знайдений, Symfony використає параметр конфігурації fallbacks, який за за замовчуванням en (див. підрозділ “Налаштування”).

Якщо Symfony не знаходить перекладу у даній локалі, тоді фреймворк додасть “загублений” переклад до лог-файлу. Детальніше див. логування у документації. 

Користування локалями користувача 

Локаль поточного користувача зберігається у запиті і доступна через об’єкт request:

use Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request)
{
    $locale = $request->getLocale();
}

Щоб налаштувати локаль потрібно створити custom event listener, щоб ця частина системи була налаштована раніше ніж вона стане потрібна прекладачеві:  

public function onKernelRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();

    // some logic to determine the $locale
    $request->getSession()->set('_locale', $locale);
}

Більше на дану тему ви зможете прочитати у статті англійською: Making the Locale "Sticky" during a User's Session. 

Встановлювати локаль у контролері за допомогою $request->setLocale() запізно, і це не подіє на перекладач. Ви можете налаштувати локаль через listener (як це вже було подано на прикладі), або через URL (наступний приклад), або напряму дайте команду setLocale() сервісові translator.

У наступному підрозділі ми розповімо про налаштування локалі за допомогою маршрутизації.

Локаль і URL 

Оскільки ви можете зберігати локаль користувача під час сеансу, можливо вам захочеться використати таку саму URL-адресу для відображення ресурсу у різних мовах, базуючись на локалі користувача. Наприклад, http://www.example.com/contact може показати контент англійською для одного користувача, а французькою для іншого. Нажаль, це порушення фундаментального правила у веб: що певна URL-адреса повертає ресурс незалежно від користувача. Ускладнимо проблему, а яка версія контенту буде індексуватися пошуковими системами?   

Найкращий варіант - залучити локаль і URL. Такий спосіб повністю підтримується системою маршрутизації і використовує спецільний параметр  _locale:

YAML

# app/config/routing.yml
contact:
    path:     /{_locale}/contact
    defaults: { _controller: AppBundle:Contact:index }
    requirements:
        _locale: en|fr|de

XML

<!-- app/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="contact" path="/{_locale}/contact">
        <default key="_controller">AppBundle:Contact:index</default>
        <requirement key="_locale">en|fr|de</requirement>
    </route>
</routes>

PHP

// app/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add('contact', new Route(
    '/{_locale}/contact',
    array(
        '_controller' => 'AppBundle:Contact:index',
    ),
    array(
        '_locale'     => 'en|fr|de',
    )
));

return $collection;

Коли ви користуватиметесь спеціальним параметром  _locale у маршруті, локаль яка підходитиме буде втоматично поставлена “on the Request” і її можна буде добути через метод getLocale(). Іншими словами, якщо користувач відвідає URI /fr/contact, локаль  fr буде автоматично налаштована для поточного запиту.

Тепер ви можете використовувати локаль для створення маршрутів, та інших перекладених сторінок у вашому додатку.  

У довіднику ви можете прочитати як уникнути хардкоду, використовуючи _locale в усіх інших маршрутах.    

Налаштування локалі за замовчуванням 

А що коли локаль користувача не була визначена? У цьому випадку ви можете гарантувати, що локаль є у кожному запиті користувача, використавши default_locale фреймворка:

YAML

# app/config/config.yml
framework:
    default_locale: 

XML

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

    <framework:config default-locale="en" />
</container>

PHP

// app/config/config.php
$container->loadFromExtension('framework', array(
    'default_locale' => 'en',
));

Перекладаємо обмеження повідомлень

Якщо ви використовуєте обмеження з компонентом Form, тоді перекласти повідомлення про помилку просто: створіть ресурс перекладу для домену валідаторів.

Напочатку уявімо, що ви створили простий PHP-об’єкт, який вам потрібно буде використовувати пізніше у додатку.  

// src/AppBundle/Entity/Author.php
namespace AppBundle\Entity;

class Author
{
    public $name;
}

Додаємо обмеження за допомогою будь-якого з методів, що підтримується. Налаштуємо опцію повідомлень до тексту, який перекладатиметься. Наприклад, щоб переконатися чи властивість $name не порожня, додайте нступне:

Annotations

// src/AppBundle/Entity/Author.php
use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\NotBlank(message = "author.name.not_blank")
     */
    public $name;
}

YAML

# src/AppBundle/Resources/config/validation.yml
AppBundle\Entity\Author:
    properties:
        name:
            - NotBlank: { message: 'author.name.not_blank' }

XML

<!-- src/AppBundle/Resources/config/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
        http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="AppBundle\Entity\Author">
        <property name="name">
            <constraint name="NotBlank">
                <option name="message">author.name.not_blank</option>
            </constraint>
        </property>
    </class>
</constraint-mapping>

PHP

// src/AppBundle/Entity/Author.php

// ...
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;

class Author
{
    public $name;

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank(array(
            'message' => 'author.name.not_blank',
        )));
    }
}

Створіть файл перекладу під каталогом validators для обмежень, а саме у  директорії пакету theResources/translations/ directory.

XML

<!-- validators.en.xlf -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="author.name.not_blank">
                <source>author.name.not_blank</source>
                <target>Please enter an author name.</target>
            </trans-unit>
        </body>
    </file>
</xliff>

YAML

# validators.en.yml
author.name.not_blank: Please enter an author name.

PHP

// validators.en.php
return array(
    'author.name.not_blank' => 'Please enter an author name.',
);

Перекладаємо контент для бази даних

Переклад контенту для баз даних повинен виконуватися за допомогою Doctrine через  Translatable Extension або Translatable Behavior (PHP 5.4+). Щоб дізнатися більше, прочитайте документацію по цих бібліотеках.  

Зневадження перекладів

Коли ви працюєте з пакетом, ви можете користуватися (або ж ні) повідомленням перекладу, і для цього не потрібно оновлювати всі каталоги повідомлень. Команда debug:translation допоможе знайти ці загублені, або невикористані повідомлення перекладів у даній локалі.  Вона покаже таблицю з результатами, коли буде використовуватися повернення. Більше того, дана команда покаже вам, коли певний переклад такий самий як і повернений переклад (це покаже, чи правильно було перекладено повідомлення).  

Завдяки екстракторам повідомлень, команда визначить використання тега або фільтра перекладу у шаблонах Twig:

{% trans %}Symfony2 is great{% endtrans %}

{{ 'Symfony2 is great'|trans }}

{{ 'Symfony2 is great'|transchoice(1) }}

{% transchoice 1 %}Symfony2 is great{% endtranschoice %}

Команда також використає наступні використання перекладу у шаблонах PHP:

$view['translator']->trans("Symfony2 is great");

$view['translator']->transChoice('Symfony2 is great', 1);

Екстрактори не в змозі перевіряти повідомлення поза шаблонами, що означає, що використання перекладача у формі міток або всередині контролерів не будуть виявлені. Динамічні переклади з участю змінних або виразів не розпізнаються в шаблонах, тобто вони не будуть проаналізовані:

{% set message = 'Symfony2 is great' %}
{{ message|trans }}

Припустимо, default_locale у вашому додатку відповідає fr і вам слід налаштувати en у якості резервної локалі (див. підрозділи “Налаштування” і “Резервні локалі перекладу”). Уявімо, що ви вже готові запустити деякі переклади для локалі  fr всередині пакету AcmeDemoBundle:

XML
<!-- src/Acme/AcmeDemoBundle/Resources/translations/messages.fr.xliff -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="1">
                <source>Symfony2 is great</source>
                <target>J'aime Symfony2</target>
            </trans-unit>
        </body>
    </file>
</xliff>

YAML

# src/Acme/AcmeDemoBundle/Resources/translations/messages.fr.yml
Symfony2 is great: J'aime Symfony2

PHP

// src/Acme/AcmeDemoBundle/Resources/translations/messages.fr.php
return array(
    'Symfony2 is great' => 'J\'aime Symfony2',
);

для локалі en:

XML
<!-- src/Acme/AcmeDemoBundle/Resources/translations/messages.en.xliff -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="1">
                <source>Symfony2 is great</source>
                <target>Symfony2 is great</target>
            </trans-unit>
        </body>
    </file>
</xliff>

YAML

# src/Acme/AcmeDemoBundle/Resources/translations/messages.en.yml
Symfony2 is great: Symfony2 is great

PHP

// src/Acme/AcmeDemoBundle/Resources/translations/messages.en.php
return array(
    'Symfony2 is great' => 'Symfony2 is great',
);

Для того, щоб визначити усі повідомлення у локалі fr для пакету AcmeDemoBundle, запустіть наступну команду:

$ php bin/console debug:translation fr AcmeDemoBundle

Ви отримаєте ось такий результат:

Це показує, що повідомлення “Symfony2 is great” не використане, тому що було перекладене, і ви його все ще ніде не використали.   

Тепер, якщо ви перекладете повідомлення в одному з шаблонів, ви отримаєте насупний результат:  

Колонка “state” порожня, і це означає, що повідомлення перекладене у локалі fr і використовуюється в одному, або ж кількох шаблонах.  

Якщо ви видалите повідомлення “Symfony2 is great” з вашого файлу перекладів для локалі fr і тоді запустите команду, ви отримаєте наступне:   

“State” показує, що повідомлення втрачене, тому що воно не перекладене у локалі fr, проте все ще використовується у шаблоні. Більше того, повідомлення у локалі fr еквівалентне повідомленню у локалі en. Це особливий випадок, адже неперекладені повідомлення в “id” відповідають перекладу в локалі en.

Якщо ви скопіюєте контент у файлі з перекладами у локалі en, до файлу з перекладами у локалі fr і запустите команду, отримаєте такий результат:

Як бачимо, переклади повідомлення у локалях fr і en іденитичні - це означає, що скоріше всього повідомлення було скопійовано з французької мови на англійську, і ви забули перекласти його.  

За замовчуванням усі домени відстежуються, проте ми можемо вказати один домен:  

$ php bin/console debug:translation en AcmeDemoBundle --domain=messages

Коли пакети містять велику кількість повідомлень, орисно відображати лише втрачені з них, використовуючи параметри  --only-unused або --only-missing:

$ php bin/console debug:translation en AcmeDemoBundle --only-unused
$ php bin/console debug:translation en AcmeDemoBundle --only-missing

Висновок

Якщо ви використовуватимете компонент Symfony Translation, тоді створення інтернаціонального дадатку не буде таким болючим процесом, і складатиметься лише з декількох основних кроків:  

1. Абстрагуйте повідомлення у вашому додатку, для цього використовуйте методи trans() і transChoice(). Про це ви можете дізнатись детальніше у розділі Використовуємо перекладач (Using the Translator);

2. Кожне повідомлення перекладайте у багато локалей; для цього створіть файли з перекладами повідомлень. Symfony знаходить і обробляє кожен файл, тому що слідує чітким правилам;

3. Керуйте локаллю користувача, що зберігається у запиті, проте її можна також розмістити у сеансі користувача.  

Поділитися