Reading time: 4 minutes
Translations and localizations in Symfony 3.4 and 4.0 (Part 2)
04 / 07 / 2019
Previously we talked about setting up the translation in our Symfony project, and some basic arrangement in our project. Today we’ll move on to talk about something more interesting. Let’s start with plural forms.
The correct choice of a translation form depending on the number of arguments is a peculiar problem. Polish is a good example. Let’s think of a list of entries with zero, one, two, or five elements. In each case, the message informing of the number will be different:
> Nie znaleziono wyników [No results found]
> Znaleziono 1 wynik [1 result found]
> Znaleziono 2 wyniki [2 results found]
> Znaleziono 5 wyników [5 results found]
Various rules apply, depending on the language; fortunately, Symfony offers a transchoice mechanism.
In order to translate such a message, simply use the following in the template:
In addition to this, relevant translation must be added, precisely specifying the ranges of values for which the relevant value should be selected:
This very simple solution resolves the plurality issue almost completely. An attentive reader, who knows polish language, will notice that this solution will not always work correctly. For instance, where 22 results are found, the message displayed will be incorrect: Znaleziono 22 wyników [22 results found].
To display the correct message, we must submit not only the quantity of records in the trans choice method but also a number specifying which translation should be used and the quantity itself as an additional parameter. Our translation should be as follows:
And, depending on the quantity of results, the appropriate form must be used:
To choose the correct translation, we will need a bit of logic to handle it. Wherever this logic is placed, you will need to remember that it will vary between languages. To check the applicable form, the following method could be used:
Correct formatting and display of dates may prove useful in our design. Please note that the commonly used format in the United States is ‘n/j/y’, while in the UK it is ‘d M Y’ and in Poland – ‘d.m.y‘. Therefore, our design must feature a service responsible for date formatting.
Exceptions are another translatable element. PHP, Symfony, and Doctrine provide plenty of various exceptions. Usually, only some of them reach the user. Problem exception content, combined with the database with an exception message containing, database name, user name, and the user’s password, should in no case be carelessly displayed to the user. When filtering exceptions to be displayed, I suggest using the white list approach.
Let us create our own exception type and display only these exceptions to the user:
In our code, wherever an exception with a content to be displayed to the user in case of an error is delated, we will be using our Parametrized Exception. The constructor of our exception has been modified, it accepts the table of parameters which will be submitted for translation. An example of a controller code to handle such an exception, could look as follows:
There are exceptions that we would like to be logged; then, the contents should be stored in the default language. Our exception handling code would then look as follows:
An the method responsible for translation into the default language:
The last issue that I would like to address is translating contents from our database. The course of action depends on the characteristics of our data model. If our project is more like a blog containing articles in various languages, and not all of them translated to other languages, I would suggest adding a column responsible for representing the language of our content table. If our database stores some simple dictionaries, such as categories or tags, you might use the following Doctrine extension: Doctrine2 behavioral extensions.
It offers the option of translating entity columns on the go. I do not recommend this solution due to its relatively slow performance but, nevertheless, it might prove sufficient for our purposes.
In the case of small tables storing tags or statuses that cannot be edited by the user, it is worth considering moving the storage of translated labels outside of the database, either by storing only translation entries in the database or by adding all these values to the code.
On the other hand, for user-editable data, it may be necessary to create another intermediate table for translations or, if the number of all operating languages of the website is known and small, adding a few columns to our table for relevant translation may be sufficient. However such an approach would greatly impede adding further translations. Sometimes, contents of subpages of various localizations in a single service do not have their mutual equivalents. Computational complexity arising from various localizations of the website may sometimes adversely affect our service. It is worth considering then putting an appropriately configured system copy for a new localization or language version.
We have briefly reviewed several localization-related issues to finally be advised to avoid the problem by duplicating the system. Our designs vary and require various solutions. It is possible that this solution will also be used at times. Everything depends on your and your design.
At Unity Group, we share our knowledge at internal meetings such as Unity Tech Talks or Coders. Should you wish to join us as a PHP programmer, feel free to read the following job offer.