Published:
24 February 2010

About Localisation

Localisation is one of Symphony’s core features. It is available for core and extension developers.

The system uses dictionaries to store translations, one per language. These are typically located at these locations:

  1. At /symphony/lib/lang for the default English dictionary,
  2. at /extensions/lang_{language-name}/lang for core translations and
  3. at /extensions/{name-of-extension}/lang for extension translations.

Symphony automatically searches for files at these places and merges all dictionaries available. Dictionaries follow a simple naming convention:

lang.{code}.php  

where {code} represents the language abbreviation. By default Symphony uses two–character abbreviations—-for example en (English), de (German), fr (French)—-but it also accepts five character abbreviation—-like en-gb (English / Great Britain) or en-us (English / United States)—-for regional differentiation. A list of valid language codes can be found at http://msdn.microsoft.com/en-us/library/ms533052(VS.85).aspx.

Dictionaries may contain two arrays:

  1. One for translation of strings, and
  2. one for transliteration of special characters (like umlauts, punctuation marks etc.)

Transliteration arrays should only be present in core dictionaries and should not be added to extension dictionaries.

If you like to provide translations for the Symphony core or its extensions, please see below.

How Does Localisation Work in Symphony?

While transliterations are just silently applied when creating handles, developers must explicitly enable string translations by using the translation function __(). This function accepts an English string, searches for its translation in the currently selected language dictionary, and returns either the translation (if found) or the original English string (if no translation was found).

When outputting text in PHP, you normally would do something like this:

echo 'This is static text.';  

The problem is that no matter what language is set in the system configuration, Symphony will always echo “This is static text.”

Using the translation function solves that problem, and it’s fairly easy to do:

echo __('This is translatable text.'); 

Now, if my current language is German, Symphony will echo “Dies ist übersetzbarer Text.” If it’s set to English, or if there is no translation available for my current language, “This is translatable text.” will be returned.

Please note: There is no English dictionary in the system——or, to be more precise, there is only an empty one. With an empty English dictionary array and a system language set to English, the translation function will return the original string which, in our case, will always be the English one.

*Please keep in mind that you need to escape single quote, e. g. __(‘Symphony’s Data Source Manager’)*

Best practices

If you would like to enable translation in your own extensions, just wrap all your strings with the translation function. But if you need more flexible strings, please keep a few things in mind:

Working with variables

The translation function accepts more than one argument:

__(string $string, array $variables)   

If you need to integrate variables into your strings, you should pass these as second argument to the translation function. This is quite important (see below) because different languages use different grammatical constructions. A single English verb, for example, can be represented in another language by a much more complex construction. Note the following examples:

Bad:

$count = $number * $things;
$output = 'There are currently ' . $count . ' things to count.';
echo __($output);

Better:

$count = $number * $things;
echo __('There are currently %s things to count.', array($count));

Best:

$count = $number * $things;
echo __('There are currently %1$s %2$s to count.', array($count, 'things'));

While the first example will create a new dictionary item for each $count, the second and third use more flexible phrases. Symphony employs PHP’s vsprintf() function in these cases.

Marking up Text

If you need to mark up text—-for example, using <strong></strong> or <em></em>—-please split up your string to leave out any HTML tags. If you leave markup in your translation strings and a translator forgets to properly close a tag, this can result in unpredictable output:

Bad:

echo __('<strong>Be aware:</strong> Markup in translations may break the back-end presentation!');

Good:

echo '<strong>' . __('Be aware') . ':</strong> ' . __('Markup in translations may break the back-end presentation!');
Don’t be Clever!

Sometimes there seem to be clever ways to combine multiple sentences in one phrase. For a long time there was this bit in Symphony’s core:

$this->pageAlert(
    __(
        '%s %s at %s. <a href="%2$s">Create another?</a> <a href="%s">View all %s</a>',
        array(
            __('Page'), 'created',
            DateTimeObj::getTimeAgo(__SYM_TIME_FORMAT__),
            URL . '/symphony/blueprints/pages/',
            __('Pages')
        )
    ),
    Alert::SUCCESS
);  

It was used for pages (like the above example), entries, sections, data sources, events and everything else that needed a page alert saying: “Something created at sometime. Create another? View all somethings?”

In whatever context this code was used, only one translation string was created:

%s %s at %s. <a href="%s">View all %s</a> 

This seemed to be quite clever—-using only one string for all contexts reduces translation work and file size. The only problem was that, unlike in English, other languages make use of male and female articles, and sometimes a single verb in English is represented by two or more words in another language. It was not possible, for example, to translate Create another? to German in a way that worked for all cases:

  1. “Create another (Data Source)?” > “Eine neue (Datenquelle) erstellen?”
  2. “Create another (Event)?” > “Ein neues (Ereignis) erstellen?”

The lesson here is not to assume that other languages can be abstracted in the same way that your own language, or English, can. Use discrete phrases, even if this results in more translation strings. If you need a string for pages, be explicit and write:

Page created at %s. <a href="%2$s">Create another?</a> <a href="%s">View all Pages</a>

If you need a string for somethings, write:

Something created at %s. <a href="%2$s">Create another?</a> <a href="%s">View all Somethings</a>

Translating the Core

As mentionded above, Symphony core translations are provided via special extensions. These have to follow a strict naming scheme as follows: lang_{language-name} where {language-name} represents the full name and not the code of your language, e. g. lang_dutch or lang_italian. If there are different local variants of your language, these should be bundled into a single language extension, e. g. lang.pt.php (Portuguese) and lang.pt-br.php (Portuguese / Brazil) should be part of the same extension.

Each language extension should contain an extension.driver.php with the extension credentials and a lang folder bundling all language files.

If you like to create a new translations, please have a look at the Localisation Manager which provides an interface for exporting and managing language files.

Translating Extensions

Extensions should provide their own translations in a lang folder inside their own file structure. Please use the Localisation Manager to export the needed strings for translation and contact the developer of the extension for integrating your language file. The easiest way is to fork the respective extension, commit the new language file, and send a pull request to the developer.

Providing JavaScript Localisation

Symphony 2.0.7 introduced functions for JavaScript string translation that mirror those in the core.

You can add custom translatable strings via JavaScript using the Symphony.Language.add function:

Symphony.Language.add({ 'The text I want to output' : false });

The function also accepts multiple strings and variables:

Symphony.Language.add({
    'The text I want to output' : false,
    'Put that {$thing} away' : false
});

When using JavaScript to output a string, you can use the Symphony.Language.get function, like this:

Symphony.Language.get('The text I want to output');

This will ensure that, when the language is not English and a translation is available, your string will be replaced with its translated equivalent. With a variable it looks like this:

Symphony.Language.get('Put that {$thing} away', { thing: 'crossbow' });

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details