Gestionando documentos multilingües

The goal of the tutorial is to describe all the steps that are needed to be taken to use multi-language documents as clearly as possible.

Por favor, primero lee esto

Lunetics LocaleBundle

The CMF recommends to rely on the LuneticsLocaleBundle to handle initial locale selection when a user first visits the site, and to provide a locale switcher.

To install the bundle, require it in your project with ./composer.phar require lunetics/locale-bundle and then instantiate Lunetics\LocaleBundle\LuneticsLocaleBundle in your AppKernel.php.

You also need the intl php extension installed and enabled. (Otherwise composer will tell you it can’t find ext-intl.) If you get issues that some locales can not be loaded, have a look at this discussion about ICU.

Then configure it in the main application configuration file. As there are several CMF bundles wanting the list of allowed locales, we recommend putting them into a parameter %locales%, see the cmf-sandbox config.yml file for an example.

Truco

Whenever you do a sub-request, for example to call a controller from a twig template, do not forget to pass the app.request.locale along or you will lose the request locale and fall back to the default. See for example the action to include the create.js javascript files in the create.js reference.

PHPCR-ODM multi-language Documents

You can mark any properties as being translatable and have the document manager store and load the correct language for you. Note that translation always happens on a document level, not on the individual translatable fields.

<?php
/**
 * @PHPCRODM\Document(translator="attribute")
 */
class MyPersistentClass
{
    /**
     * Translated property
     * @String(translated=true)
     */
    private $topic;

Read more about multi-language documents in the PHPCR-ODM documentation on multi-language and see Configuración de traducción to configure PHPCR-ODM correctly.

Most of the CMF bundles provide multi-language documents, for example MultilangStaticContent, MultilangMenuNode or MultilangSimpleBlock. The routing is different, as explained in the next section.

Enrutado

The DynamicRouter uses a route source to get routes that could match a request. The concept of the default PHPCR-ODM source is to map the request URL onto an id, which in PHPCR terms is the repository path to a node. This allows for a very efficient lookup without needing a full search over the repository. But a PHPCR node has exactly one path, therefore we need a separate route document for each locale. The cool thing with this is that we can localize the URL for each language. Simply create one route document per locale, and set a default value for _locale to point to the locale of that route.

As all routes point to the same content, the route generator can handle picking the correct route for you when you generate the route from the content. See also ContentAwareGenerator y regiones.

Sonata PHPCR-ODM Admin

This section explains how to make Sonata Admin handle multi-language documents. You should already have set up Sonata PHPCR-ODM Admin and understand how it works, see Creating a CMS using the CMF and Sonata.

Nota

The following assumes that you installed the LuneticsLocaleBundle as explained above. If you want to use something else or write your own locale handling, first think if it would not make sense to give the Lunetics bundle a try. If you are still convinced you will need to adapt the following template examples to your way of building a locale switcher.

The first step is to configure sonata admin. We are going to place the LuneticsLocaleBundle language switcher in the topnav bar. To do this we need to configure the template for the “user_block” as shown below:

  • YAML
    # app/config/config.yml
    sonata_admin:
        ...
        templates:
                user_block: AcmeCoreBundle:Admin:admin_topnav.html.twig
    

Y la plantilla se ve como esta

{# src/Acme/CoreBundle/Resources/views/Admin/admin_topnav.html.twig #}
{% extends 'SonataAdminBundle:Core:user_block.html.twig' %}

{% block user_block %}
    {{ locale_switcher(null, null, 'AcmeCoreBundle:Admin:switcher_links.html.twig') }}
    {{ parent() }}
{% endblock %}

We tell the locale_switcher to use a custom template to display the links, which looks like this:

{# src/Acme/CoreBundle/Resources/views/Admin/switcher_links.html.twig #}
Switch to :
{% for locale in locales %}
    {% if loop.index > 1 %} | {% endif %}<a href="{{ locale.link }}" title="{{ locale.locale_target_language }}">{{ locale.locale_target_language }}</a>
{% endfor %}

Now what is left to do is to update the sonata routes to become locale aware:

  • YAML
    # app/config/routing.yml
    
    admin_dashboard:
        pattern: /{_locale}/admin/
        defaults:
            _controller: FrameworkBundle:Redirect:redirect
            route: sonata_admin_dashboard
            permanent: true # este para 301
    
    admin:
        resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
        prefix: /{_locale}/admin
    
    sonata_admin:
        resource: .
        type: sonata_admin
        prefix: /{_locale}/admin
    
    # redirige las rutas a las rutas no regionales
    admin_without_locale:
        pattern: /admin
        defaults:
            _controller: FrameworkBundle:Redirect:redirect
            route: sonata_admin_dashboard
            permanent: true # este para 301
    
    admin_dashboard_without_locale:
        pattern: /admin/dashboard
        defaults:
            _controller: FrameworkBundle:Redirect:redirect
            route: sonata_admin_dashboard
            permanent: true # este para 301
    

When we now reload the admin dashboard, the url should be prefixed with our default locale, for example /de/admin/dashboard. When clicking on the language switcher the page reloads and displays the correct content for the requested language.

The provided sonata admin classes map the locale field of the multi-language documents to the form. You need to do the same in your admins, in order to create new translations. Otherwise the language fallback of PHPCR-ODM will make you update the original language, even when you request a different locale. With the mapped locale field, the editor can chose if he needs to create a new language version or updates the loaded one.

Happy editing.

Frontend editing and multi-language

When using the CreateBundle, you do not need to do anything at all to get multi-language support. PHPCR-ODM will deliver the document in the requested language, and the callback URL is generated in the request locale, leading to save the edited document in the same language as it was loaded.

Nota

If a translation is missing, language fallback kicks in, both when viewing the page but also when saving the changes, so you always update the current locale.

It would make sense to offer the user the choice whether he wants to create a new translation or update the existing one. There is this issue in the CreateBundle issue tracker.

Bifúrcame en GitHub