Setting up a multilingual site

Setting up a multilingual site

The official documentation can once more be found in the SilverStripe docs here.

Just to be confusing: Translatable in SilverStripe lingo means multilingual as in 'a site in more then one language'. Translatable is meant to be a separate module as of version 3.0, you can find the new documentation on github: Translatable documentation on github

'The Book' dedicates an entire section to Translatable. See also the ssbits tutorial. Finally, a lot of information can be found in the header of the Translatable class file itself (sapphire/core/model/Translatable.php).

Note: whether Translatable or not, it is always a good idea for modules and objects to be properly internationalized.

Step 1 - enable Translatable

Before enabling the Translatable module, there are two things that need doing:

  • Decide what the default (master) Locale will be.
  • Decide which objects you want to be able to translate. Initially that will at least be the SiteTree (all pages) and the SiteConfg, where footers and headers and such may be stored

Important: always set the default locale first: it will be used to localize the existing website on /dev/build! Having set i18n::set_locale('xx_XX'); is not enough - SilverStripe will still revert to en_US!!!

Put the following in /mysite/_config.php, then do a /dev/build/?flush=1

// Set the default locale for a multi-lingual site
Translatable::set_default_locale('en_US');

// Define which objects you wish to include in your translations (can be any DataObject)
Object::add_extension('SiteTree', 'Translatable');
Object::add_extension('SiteConfig', 'Translatable');

This will create the so called translationgroups tables in the databas: one for each translatable object, where the relationship between the different versions of a translated object will be stored. In this case we'll have two new tables: SiteTree_translationgroups and SiteConfig_translationgroups.

Step 2 - available languages

Ons Translatable is enabled, an extra tab 'Translations' is now present for each page in the CMS, displaying what translations already exist for the page - and a 'select a new translation from a language' dropdown (note that existing languages no longer appear in the dropdown).

Restrict the number of available languages

The number of available languages in the LanguageDroptdownField is hughe, but you can limit them by setting the i18n::$common_locales in your mysite/_config.php:

// Set the number of language you wish to have available
i18n::$common_locales = array(
	'nl_NL' => array('Dutch', 'Nederlands'),
	'en_US' => array('English (US)', 'English (US)'),
	'fr_FR' => array('French', 'français'),
	'de_DE' => array('German', 'Deutsch'),
	'it_IT' => array('Italian', 'italiano'),
	'es_ES' => array('Spanish', 'español')
);

Step 3 - translate a page

Select a page in the root, that has a couple of children (not the homepage) and add a new translation for it - say Dutch. This automatically leads to a totally new SiteTree, that has only the one page available. A language dropdown at the top of the SiteTree tells me that I'm now editing pages on my Dutch site. I can now also access the Dutch SiteConfig, where I can define all global settings for the Dutch websit - including a different template.

Translate a childpage

Childpages are not automatically included in the new translation, you must translate them separately. SilverStripe will remember its parent in the translated site, so it will automatically be created in the right spot in the Dutch site+. The other way around: if you start by creating a childpage, SilverSAtripe will include parent pages in the translation - up until the root!

So can I create a translation for an entire tree all at once? Unfortunately: no. SilverStripe doesn't care about sibblings, it's just the path down to the root that gets created.

Reverse translation

The other way around works just as well: add a (childpage) to a page in the Dutch site, and then translate it for the default English language - SilverStripe still 'knows' where it should be.  

There are lots of configurations I could test now - what if I move pages around in the new language, leaving them as they were in the old one? This should make no difference - translated pages live in a common group called a 'TranslationGroup' (more later), identified by their ID's. A page that is part of such a group is considered a translation, never mind a different location or parent. But it would make keeping up the site extremely complex, so you probably shouldn't...

Step 4 - setting the locale from the querystring

Every page on the website - be it English or Dutch or..., is just an ordinary page and in reality all pages live on one and the same website. Still there is a fixed relation between pages that are 'each others translation'. This makes it possible to simply go from one page to one of its translations by just adding the required locale to the querystring. So suppose the following two pages are translations of one and the same page:

  • http://mydomain/englishpage
  •  http://mydomain/dutchpage

Then http://mydomain/dutchpage?locale=en_US will redirect to http://mydomein/englishpage (watch the url) - and the other way around will work as well.

Homepage

The same goes for the homepage. There can only be one page that has 'home' for its urlsegment and that is the page that's displayed when the webroot is requested in the url. But here too, adding the locale in the querystring will display the translated homepage - as long as it was added as a translation of the original homepage, and not created separately! In this case it's not a redirect as such - the querystring stays visible.

Default homepage:

http://mydomain.xx/

Homepage other language:

http://mydomain.xx/?locale=xx_XX

Why is all this useful? I's an easy way to direct a user to a translation of the page he's currently on, without having to know the actual urlsegment of that page. This will only work for pages that are 'connected' as translations.

Step 5 - HTLM language setting

Remember to set the correct language in the lang attribute of the HTML header. This cannot be done by using the Translatable currentlocale directly, you need to set the i18n locale in the Page_Controllers init() function separately:

public function init() {

	parent::init();

	if($this->dataRecord->hasExtension('Translatable')) {
		i18n::set_locale($this->dataRecord->Locale);
	}
	...
}

Now you can use $ContentLocale in the page template to create the locale: it will convert en_US to en-US for you. Example:

<html lang="$ContentLocale" xmlns="http://www.w3.org/1999/xhtml">

Step 6. Set up a language switcher

Function: getTranslations($locale = null, $stage = null)

This will get you a DataObjectSet of all translations for the current object, except for the current locale. If an (optional) locale is added as a param, it will only query for that special locale. If versioned is enabled for the object, you can provide a stage as well (Live, Stage); Unfortunately you cannot influence the order in which the translations are retreived. Try this in your Page template:

<% if Translations %>
<ul>
	<% control Translations %>
		<li><a class="$Locale" hreflang="$Locale.RFC1766" href="$Link">$Locale</a></li>

	<% end_control %>
</ul>
<% end_if %>

Note: This is (just) one way to create a language switcher. For some reason, if the if-control is omitted, SilverStripe will still loop once if no translations are available. Never knew why that should be so...

Comments

Het versturen van reacties is uitgeschakeld.

RSS feed voor reacties op deze pagina