Tutorials - Big bits of code to help you do more
Using Translatable to create a Simple Multilingual Site
Tweet9 April 2011 | | | Supports v2.4
I recently had a request to build a multilingual site for an accountant who wanted to enter content in English, Romanian and Russian, and wanted their site visitors to be able to switch languages by clicking on the image of the country flag - and I was pleasantly surprised to learn how quick and easy it is to implement using Silverstripe's Translatable class.
1. Set the default site locale
For me, I'm based in the UK, so my default local is en_GB, so in /mystie/_config.php, I added:
// Set the site locale
i18n::set_locale('en_GB');
2. Enable Translations in Silverstripe (Translatable)
Add the following lines to the /mysite/_config.php file
//default translation
Translatable::set_default_locale('en_GB');
/* restrict the language select dropdown in the admin
to only those languages that you will actually use.
In my case, UK English, Romanian and Russian */
Translatable::set_allowed_locales(array(
'en_GB', //UK English
'ro_RO', //Romanian
'ru_RU' //Russian
)
);
3. Make your SiteTree and SiteConfig Translatable
SilverStripe needs to know which parts of our site we want to Translate so we tell it by adding the following to mysite/_config.php:
Object::add_extension('SiteTree', 'Translatable');
Object::add_extension('SiteConfig', 'Translatable'); // 2.4 or newer only
Now run /dev/build/ to rebuild the Database with the relevant translateable fields.
4. Add a simple language switcher to your template
Now that our site is translatable, we need to let users switch between languages so add this to your site template, (e.g. themes/yourtheme/templates/Page.ss):
<% if Translations %>
<div id="lang" class="clear">
<ul class="clear">
<% control Translations %>
<li>
<a href="$Link" hreflang="$Locale.RFC1766" title="$Title - $Locale.Nice">
<img src="$ThemeDir/images/lang-<% sprintf(_t('IMAGE','%2.2s'),$Locale.RFC1766) %>.gif">
</a>
</li>
<% end_control %>
</ul>
</div>
<% end_if %>
Incase you are wondering, RFC1766 is an ISO Language Identification Code Standard in which they have a "TAG" (not in the HTML/XML sense) for each language to identify what language is spoken and in what region. The language code list can be downloaded in CSV and Spreadsheet format here. However, Silverstripe uses underscores in the language code to seperate the language from the region in which it is spoken - and it also uses Uppercase letters for the region, so I have put together a simple Excel spreadsheet of Language codes available.
5. Add your flag images to the theme images folder,
Carefully following the naming convention used in the previous step add the flag images to themes/yourtheme/images.
In my case, I used the following image names:
lang-en.gif (UK flag for English language)
lang-ro.gif (Romanian flag)
lang-ru.gif (Russian flag)
Remember to flush your site template cache by adding /?flush=1 to the url.
6. Create your pages in the SiteTree.
To add content other languages, use the new 'Translations' tab in the admin and off you go!
7. (Optional) Make DataObjects Translatable
To make a DataObject translatable, you must add the following to your mysite/_config.php:
Object::add_extension('MyDataObject', 'Translatable');
Don't forget to run a /dev/build to rebuild the database afterwards.
Please note: When creating dataobjects in other languages, there is currently a bug in translatable causing all dataobjects to be added to the database using the default locale rather than selected locale. In my case, I had to manually change the locales of the Romanian and Russian dataobjects in the database table from en_GB to en_RO and en_RU, respectively the very first time that I created the dataobject in a language other than the default.
That's all! Good luck with creating your multilingual site!
Related Links
SilverStripe rfc1766 Language Identification Codes spreadsheet
Special Thanks
Special thanks go to Aram Balakjian for their contributions to this post.
32 Comments
RSS feed for comments on this page RSS feed for all comments
Darren-Lee
09/04/2011 6:58pm (2 years ago)
Apologies for typo in the above post - locales, "en_RO" and "en_RU" should say "ro_RO" and "ru_RU", respectively. I get Aram to change it.
dendeffe
11/04/2011 9:46am (2 years ago)
Nice write up Darren. Certainly easier then the language switcher I'm using now. Will have to give this a try.
swaiba
11/04/2011 9:46am (2 years ago)
Just a quick note that I've used this method as it comes straight out of the SS book. the flags are available here... http://www.famfamfam.com/lab/icons/flags/
Darren-Lee
11/04/2011 10:29am (2 years ago)
@dendeffe - Thanks - I'm encouraged as this is my first SSbits write-up.
@swaiba - I can't believe it! Don't you just hate it when that happens? I had to go trawling through the forums for these answers - and all the time it was sitting in my SS book right under my nose! Next time I'll try the book first :) Many thanks for the link to the flags - very useful.
swaiba
11/04/2011 10:43am (2 years ago)
no problem - I've posted a bit of this on the forum from time to time - no I can just link to this :)
I re-read the book every now again and normally find something new/useful that I'd forgotten since the first read.
Marcus Dalgren
11/04/2011 10:40pm (2 years ago)
For anyone doing a multilingual site keep in mind that entity translations (common in some modules) don't use the Translatable locale, they use the i18n locale. On the public site you probably want the entity translations to match the Translatable locale so set i18n locale = Translatable locale in your controller.
Morven
16/04/2011 1:53am (2 years ago)
Very comprehensive writeup, got a couple of these sites in the pipline. Hopefully this will make my life a bit easier :)
Darren-Lee
16/04/2011 12:11pm (2 years ago)
@Mo - cheers, dude. Glad you think this can help.
@Marcus - thanks for the tip. Do you think, you can post an explicit example of what you mean for the benefit of all...? Even if you only post the one-line of code that goes into the controller, I'm sure many will find it helpful/useful. Many thanks.
spyrosk
21/04/2011 9:13am (2 years ago)
Hi Darren, really nice work, thank you!
Quick question though, have you been able to change your url's to include non-Latin words? Or are they being transformed like this:
www.yoursite.com/page-5/page-20
I've been searching for this for quite some time but haven't been able to solve it.
Darren-Lee
21/04/2011 11:57am (2 years ago)
@spyrosk - glad you find it useful.
I've not tried to change url to include non-latin words.
On the site that I did, the English looks like this:
http://www.yoursite.co.uk/services/
the Romanian looks like this:
http://www.yoursite.co.uk/services-ro-RO/
...and the Russian looks like this:
http://www.yoursite.co.uk/services-ru-RU/
The other way of accessing the other translations is like this:
English (same as above)
Romanian: http://www.yoursite.co.uk/services/?locale=ro_RO
Russian: http://www.yoursite.co.uk/services/?locale=ru_RU
Not sure if this answers your question or even helps you at all...
If I've understood you correctly, are you saying that if one of your languages were Russian, you would like to see Russian characters in the URL?
spyrosk
21/04/2011 2:21pm (2 years ago)
Yes, although it's not a Russian site, I would like to be able to have non latin urls, which are beneficial to search engine rankings, but haven't been able to do so.
Here's the thread in the forums in which I'm asking this as well:
http://www.silverstripe.org/general-questions/show/15769
From my understanding it has to do with SS's allowed characters in the urls but I haven't found a solution yet.
Thank you again!
Pali
24/04/2011 2:22pm (2 years ago)
dont use i18n setup in mysite/_config.php, but place it in Page_Controller's init() method:
if($this->dataRecord->hasExtension('Translatable')) {
i18n::set_locale($this->dataRecord->Locale);
setlocale(LC_TIME, $this->dataRecord->Locale . ".utf8");
}
so entity translations will match Translatable locale...
Kafil
26/05/2011 1:21pm (2 years ago)
Hi Darren
I am a silverstripe beginner, you tutorial helped me a lot.
I wanted to know if it is possible to have url like
http://www.yoursite.co.uk/RO/services
instead of
http://www.yoursite.co.uk/services-ro-RO/
so http://www.domain.com/lang/page
I am using silverstripe 2.4.5
Darren-Lee
26/05/2011 11:19pm (2 years ago)
Hi Kafil,
Glad you found the post helpful. There are several different ways to do what you need. The following posts come to mind.
1) http://silverstripe.org/archive/show/4221
2) http://doc.silverstripe.org/old/recipes:multilingual_content
I have also read posts by people who have created a language node in the root of the sitetree for each language and then created pages under each of the language nodes in the appropriate language.
I hope this helps.
Kafil
01/06/2011 6:18pm (2 years ago)
Hi Darren,
Thanks for the links , will try the methods mentioned in there and see if i can achieve what i want :)
swaiba
05/07/2011 7:16pm (2 years ago)
Want widgets with that?
http://silverstripe.org/widgets-2/show/11375
Axel Larator
06/07/2011 8:24pm (2 years ago)
Hello Darren,
I followed the same thoughts, but made some tiny modifications, which I found in several SS related documentations.
My website is in German/English and the language switching works like a charm. The translation of the pages is done via the Admin tool.
The switch between German and English is done via <% control Translations %> in the footer section ( <% if Locale == "de_DE" %> ), done on the page level.(i.e. Impressum == Imprint).
Plus an URL pointer in the sidebar, that points to the homepage of the other language. Take a look at valuegrid.com or valuegrid.de.
In MyPage
Translatable::set_default_locale('de_DE');
Translatable::enable();
Translatable::set_default_lang('de');
Object::add_extension('SiteTree', 'Translatable');
Object::add_extension('SiteConfig', 'Translatable'); // 2.4 or newer only
Translatable::set_allowed_locales(array('de_DE', 'en_US'));
// Set the site locale
// i18n::set_locale('de_DE');
// set the current locale based on the current translation language
i18n::set_locale(Translatable::get_current_locale());
switch(Translatable::get_current_locale()){
case 'de_DE':
setlocale(LC_TIME, 'de_DE', 'de_DE.UTF8', 'German', 'de-DE');
break;
case 'en_US':
setlocale(LC_TIME, 'en_US', 'en_US.UTF8', 'English', 'en-US');
break;
}
Wezzlee
06/07/2011 9:16pm (2 years ago)
Hi thanks for the guide. This really helped me out. There is only one problem. I also use the ImageGallery module and this method does not seem to work with this module :( Anyone suggestions?
Wezzlee
06/07/2011 9:25pm (2 years ago)
Never mind I already figured out what was causing the problem.
Wezzlee
06/07/2011 9:25pm (2 years ago)
Never mind I already figured out what was causing the problem.
Darren-Lee
10/08/2011 10:58pm (2 years ago)
@Pali - thanks for sharing. Sorry I did not acknowledge your post before.
@Axel - thank you so much for sharing - that's the spirit of the SilverStripe community.
@Wezzlee - so you had a problem with the ImageGallery and then you solved it... did you ever think about sharing in a bit more detail about the problem you faced and then sharing the solution too? I think it would help the community to know a bit more about the problem you faced and what you did to solve your problem...
lerni
26/08/2011 9:00am (2 years ago)
To make DataObjects work with Translatable & DataObjectManager I've put a onBeforeWrite hook in the DataObjects. like...
public function onBeforeWrite() {
parent::onBeforeWrite();
$this->Locale = Translatable::get_current_locale();
}
and also used this patch:
http://open.silverstripe.org/attachment/ticket/4199/2.4.2-Translatable-FormField-controller-hack.diff
what other/smarter solutions do others use?
Steven
14/11/2011 2:44pm (2 years ago)
Hello Darren,
Maybe you can help me with this, since nobody could on the Silverstripe forum.
How can you make Silverstripe see what your current language is using the t_ function?
I tried translating a site, but it only works half. I use the dropdown on the left to switch between languages (I don't use the tab "Translations") and that works. Also, I have a translation file in the mysite/lang/ folder for the parts I want translated in mij .ss files. That also works, but only for the default language. Making a second translation file and switching between languages doesn't work unfortunately.
In the .ss code I use this;
<% _t('ProductHolder.VIEW','View') %>
And in the translate file I use this;
$lang['nl_NL']['ProductHolder']['VIEW'] = 'Toon';
So, for nl_NL it works, but when I do this;
$lang['en_GB']['ProductHolder']['VIEW'] = 'View';
It doesn't work when I go to the English page.
It seems the template doesn't see which language the user is in.
Best regards,
Steven
Adil Aliyev
28/01/2012 9:44pm (1 year ago)
Great. It helped me.
If_Else
31/01/2012 1:46pm (1 year ago)
Hello,
I' trying to build a linking widget for internal links but can't get a tranlslatable Sitetree to work right it keeps showing my default locale.
Can anybody help me
Aaron
08/03/2012 4:59pm (1 year ago)
Hi guys,
Im new round these parts, trying to get Translatable to work on my Silverstripe website, I have followed this tutorial and have 3 site trees with various pages all successfully translated, however every word is in my default (english) across all the sites?? I cannot work it out.
I am using version 2.4.6 and like I said have all the code from the tutorial in place but unfortunately none of the content is being translated at all.
Does anyone have any ideas why this could be? I thought possibly due to the doc type not being set correctly although this and all meta tags, utf-8 etc are all standard from installation as never touched them.
Would really appreciate any advice or suggestions on this as really puzzled.
Thanks :)
ps - great website and resources for someone new to Silverstripe, well done
ilovemoon
10/04/2012 11:57am (1 year ago)
Hi Darren,
This is a great help, thanks so much.
Is there a way to detect if a visitor is visiting from a country (say Spain) and giving them that language without them having to click on the flag?
siorp
20/03/2013 10:27am (3 months ago)
Hi all! Hope someone can help me.
I've installed a SS 3.0.5, the translatable module, follow this very helpful post and the blog module. Everything seems to work fine but the template blog that doesn't change the language of "posted by..." the date format etc.
I read a lot of posts but I am too dummy to solve the problem. Can someone help me?
In my my site/_config.php I've set:
i18n::set_locale('de_DE');
Translatable::set_default_locale('de_DE');
Translatable::set_allowed_locales(array('de_DE', 'it_IT', 'en_US'));
// Important: Call add_extension() after setting the default locale
Object::add_extension('SiteTree', 'Translatable');
Object::add_extension('SiteConfig', 'Translatable');
But still the template doesn't change when I switch to another language.
Any idea?
Thanks in advance.
Pier
siorp
20/03/2013 10:31am (3 months ago)
PS you can see the website I am working to here: sitiper.it/blog
Timothy
05/06/2013 4:58am (14 days ago)
Thank you so much this was too easy! I spent ages trying to figure it out with the official docs, then I found your post. You put it in such a straightforward way unlike the official. Very much appreciated!
Timothy
05/06/2013 10:29pm (13 days ago)
Do you have an example of how to use the _T() function in a .js file?
ie.
$('#Form_ContactForm_LastName').attr("placeholder", "Nom *");
What I want to be able to do is something like:
$('#Form_ContactForm_LastName').attr("placeholder", "_t('Page.LastName', 'Last Name')");
?
Timothy
05/06/2013 10:29pm (13 days ago)
Do you have an example of how to use the _T() function in a .js file?
ie.
$('#Form_ContactForm_LastName').attr("placeholder", "Nom *");
What I want to be able to do is something like:
$('#Form_ContactForm_LastName').attr("placeholder", "_t('Page.LastName', 'Last Name')");
?
Post a comment ...
You cannot post comments until you have logged in. Login Here.