Interface translation in symfony

Symfony provides interface translation using the XLIFF standard. While using the XLIFF standard here is good, it has one pain point. The pain point becomes apparent when the need arises for changing/editing the phrases. If the phrase is used in several templates, you need to search all the templates and change there as well as in the dictionary.

For example, lets say we define a simple label like “Username” in the dictionary and in several templates. The dictionary will look like:

<?xml version="1.0" ?>
<xliff version="1.0">
  <file orginal="global" source-language="en_US"
    datatype="plaintext">
    <body>
      <trans-unit id="1">
        <source>Username</source>
        <target>ユーザー名</target>
      </trans-unit>
    </body>
  </file>
</xliff>

And in all templates that use the label “Username” we will use the following to translate it based on user’s culture:

echo __('Username');

This is good, but lets say down the line we decide to use the label “User Id” instead of “Username”. To do that we need to update all the templates and the dictionary. This becomes cumbersome if you have a large number of templates that reference this label. If you notice, the cause of the problem lies in the fact that we have used the actual text itself to identify the i18n phrase within all templates.

To get around this problem, what we did was to use a code to identify the phrase and use that in the template. And we provide a dictionary for each of the supported language. So in this case we create an English and Japanese dictionary both. But what about the source language, you would ask. Well, thats a hack: we ended up providing a non existent ISO code. Based on the comment from Dennis, we use English as the source since translation happens even if source and target languages are same.

So here is what our English and Japanese dictionary look like:

<?xml version="1.0" ?>
<xliff version="1.0">
  <file orginal="global" source-language="en_US"
    datatype="plaintext">
    <body>
      <trans-unit id="1">
        <source>LABEL_USERNAME</source>
        <target>Username</target>
      </trans-unit>
    </body>
  </file>
</xliff>

<?xml version="1.0" ?>
<xliff version="1.0">
  <file orginal="global" source-language="en_US"
    datatype="plaintext">
    <body>
      <trans-unit id="1">
        <source>LABEL_USERNAME</source>
        <target>ユーザー名</target>
      </trans-unit>
    </body>
  </file>
</xliff>

And the phrase in the template looks like:

echo __('LABEL_USERNAME')

So now if you want to change the English version of the phrase, you simply update the dictionary and no need to change the templates.

5 Responses to “Interface translation in symfony”

  1. Dennis Says:

    There is a more clean way (in my opinion) to do this:
    You don’t need a non-existing source code. It is possible to translate from source language to the same language as target.

  2. Shyamal Says:

    Thanks for the tip Dennis. Will update the main article with your suggestion.

  3. arvind Says:

    hi , i have done all the setting , but still it not working
    my setting is :
    is have used config/i18n/messages.hi.xml ,

    can u give me the code and procedure for changing the text code by symfony

  4. Shyamal Says:

    Arvind, you need to keep the files under the i18n directory directly under the root project folder. It is not to be kept in the config folder.

    So the directory will look something like:

    myProject
    |--apps
    |--batch
    |--config
    |--data
    |--i18n
    |  |--messages.en.xml
    |  |--messages.en.xml
    |
    |--lib
    |--web

    Alternatively, you could keep the whole i18n folder under the application folder, for example under myProject/apps/frontend/i18n

  5. Start IT up » Blog Archive » Interface translation in symfony - tool for teams Says:

    […] mentioned in my previous post how we decouple the translation dictionary completely from the source so that a change in any text […]

Leave a Reply