Стандартная локализация, которая предоставляется в Symfony 2.4
, подразумевает изменение локали через URI
. Например, переводы страниц будут доступны по таким ссылкам:
localhost/symtest/en/homepage localhost/symtest/uk/homepage localhost/symtest/ru/homepage
Предлагаемый по умолчанию механизм локализации, реализуется в Symfony 2.4
довольно просто.
1. Настройка
В настройках, в файле app/config/config.yml
, нужно указать локаль отката:
framework: #... translator: { fallback: en } #...
Локаль отката используется в случае, если для какой то локали не определён перевод. В таком случае будет загружаться локаль отката.
2. Маршруты
Каждый маршрут должен иметь один параметр по умолчанию и выглядеть приблизительно так:
homepage: pattern: /{_locale} defaults: { _controller: SiteMemberBundle:Default:index, _locale: en } requirements: _locale: en|ru|uk
или так:
store_editproduct: pattern: /{_locale}/store/editproduct/{id} defaults: { _controller: SiteStoreBundle:Default:editproduct, _locale: en } requirements: id: \d+ _locale: en|ru|uk
Этот параметр по умолчанию указывает на локаль которая должна загружаться, если она явно не указана в ссылке. Например, ссылки вида:
/ /store/editproduct/3
будут загружать английскую локаль.
Как видно из примеров, в каждом маршруте на параметр _locale
накладывается ограничение вида: en|uk|ru
. Благодаря этому, попытка загрузить локаль, которая не входит в список ограничения, вызовет код ошибки 404
.
Таким образом, если нужно изменить локаль по умолчанию, или добавить новую к списку ограничения, необходимо пройтись по всех маршрутах и изменить соответствующие параметры. Чтобы избежать лишней работы, нужно считывать значения этих параметров из файла app/config/parameters.yml
. При создании проекта параметр locale
создается по умолчанию, а параметр available_langs
(название произвольное) необходимо создать самому. В результате, каждый маршрут следует оформлять в таком виде:
store_editproduct: pattern: /{_locale}/store/editproduct/{id} defaults: { _controller: SiteStoreBundle:Default:editproduct, _locale: %locale% } requirements: id: \d+ _locale: %available_langs%
Существует более оптимальный подход централизации параметра _locale
. В файле app/routing.yml
, для каждого подключаемого бандла прописывать следующее:
site_store: resource: "@SiteStoreBundle/Resources/config/routing.yml" prefix: /{_locale} requirements: _locale: %available_langs%
после чего, маршрут нужно строить таким образом:
store_editproduct: pattern: /store/editproduct/{id} defaults: { _controller: SiteStoreBundle:Default:editproduct, _locale: %locale% } requirements: id: \d+
3. Файлы переводов
Файлы переводов, следует размещать в каталоге Resorces/translations
соответствующего бандла. Для того, чтобы структурировать файлы переводов - например, можно сделать так, что каждый шаблон будет иметь свой файл перевода - нужно использовать домены в названиях файлов. Допустим есть такие шаблоны:
Resources/ views/ Default/ template_1.html.twig template_2.html.twig layout.html.twig
и нужно локализовать их на два языка: ru
и en
. В таком случае необходимо создать такие файлы переводов:
Resources/ translations/ layout.en.yml layout.ru.yml template_1.en.yml template_1.ru.yml template_2.en.yml template_2.ru.yml
Доменом называется первая часть названия файла, в данном случае это: layout
, template_1
и template_2
.
Если нужно локализовать глобальные шаблоны, например, основной шаблон сайта, app/Resources/views/base.html.twig
, то следует создать каталог app/Resources/translations
и поместить туда файлы переводов для этих шаблонов.
4. Функции перевода
Каждое сообщение, которое нужно перевести, следует передать в функцию перевода, которая переведет это сообщение в соответствующую локаль.
- В контролере следует использовать такую конструкцию:
$this->get('translator')->trans('message', array(), 'domain');
- В шаблоне перевод выполняется таким образом:
{% trans from "domain" %}message{% endtrans %}
- В форме сервис транслятора используется автоматически, поэтому не нужно явно использовать функции перевода в классе формы. Но, чтобы указать домен файла перевода, нужно переопределить метод
setDefaultOptions
таким образом:public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'translation_domain' => 'manageprod', )); }
5. Смена локали
Чтобы дать пользователю возможность менять локаль, можно пойти двумя путями.
- Первый способ состоит в том, чтобы создать простые ссылки вида:
<ul class="lang-menu"> <li> <a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': 'ru'})) }}" >{% trans %}language.ukrainian{% endtrans %}</a> </li> <li> <a href="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': 'en'})) }}" >{% trans %}language.english{% endtrans %}</a> </li> </ul>
Таким образом, пользователь будет переадресовываться на текущую страницу и локаль поменяется.
Такой вариант полезный тем, что работает даже в том случае, если отключён
JavaScript
. Если же проектом предусмотрено, что у пользователя должен быть включёнJavaScript
, то можно пойти другим путём. - Второй способ - создать выпадающий список и при выборе из него конкретного значения менять локаль. Для этого нужно использовать такой код:
<select id="lang" onchange="location=this.options[this.selectedIndex].value;"> <option value="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': 'ru'})) }}" >Русский</option> <option value="{{ path(app.request.get('_route'), app.request.get('_route_params')|merge({'_locale': 'en'})) }}" >Английcкий</option> </select>
Когда пользователь выберет из списка какое то значение, то произойдет перезагрузка страницы на текущую и , чтобы установить в списке выбранную им локаль, нужно использовать код:
<script type="text/javascript"> $(document).ready(function(){ $("#lang [value='{{ path(app.request.get('_route'), app.request.get('_route_params')| merge({'_locale': app.request.get('_locale')})) }}']") .attr("selected", "selected"); }); </script>
Супер! Спасибо!
ОтветитьУдалить