You are not logged in Log in Join
You are here: Home » Members » CodeSyntax » Tips for multilingual websites, using DTML and Localizer

Log in
Name

Password

 

Tips for multilingual websites, using DTML and Localizer

These tips may be useful when creating bilingual or multilingual websites that use Localizer, that nice i18n/l10n product for Zope. The tips are not for product i18n or product l10n, which is another of the uses of Localizer: they're just for multilingual websites.

You need Localizer to try all this, of course. Download it and install it, if you haven't yet.

Tip # 1: Get the selected language locale.

Inside Localizer, create a Python Script named selected_language

Add accept_language in the parameter list and then this in the body

request = container.REQUEST
available_languages = container.get_available_languages()
default_language = container.get_default_language()
selected_language = accept_language.select_language(available_languages) or default_language
request.set('SELECTED_LANGUAGE', selected_language)

Then, go to the Localizer folder, choose properties, and add selected_language to accept_methods

After that, you can add <dtml-var SELECTED_LANGUAGE> wherever you want to get the locale symbol.

When would you need that? For instance, to mark the language shown in the html head, you can dot that with this:
<META HTTP-EQUIV="Content-Language" CONTENT="<dtml-var SELECTED_LANGUAGE>">


This tip is also needed to perform most of the other tricks described in this tip collection.

Tip # 2: Best way to show content that is different in each language

Just use the LocalContent objects. Add them from the "add type" pulldown menu. If inside a Folder named Kuku you add a LocalContent object named index_html that's what the user will see when pointing to www.foo.com/Kuku

LocalContent objects are displayed according to the template defined in the default_template DTML method.

A simple and effective configuration for the default_template is this:

<dtml-var standard_html_header>
<h1><dtml-var title></h1>
<dtml-var body fmt=structured-text>
<dtml-var standard_html_footer>

Try it, and then write the content in LocalContent as structured text. It's easy and practical.

Tip # 3: Display option-menu of available languages:

<dtml-var "Localizer.changeLanguageForm()">

Tip # 4: Display another option-menu of available languages:

Display option-menu of available languages, with the option to touch the language names through a MessageCatalog named myMessageCat:

<form name="langform" action="<dtml-var "Localizer.absolute_url()">/changeLanguage" method="post">
<select name="lang" onchange="langform.submit()">
<dtml-in "Localizer.get_languages_map()" mapping>
<option value="<dtml-var id>"<dtml-if selected> selected</dtml-if>><dtml-var "myMessageCat(title, id)"></option>
</dtml-in>
</select
</form>

Why would anyone use the menu of tip # 4 instead of the much simpler previous one?

Well, the language names with the first menu are always localised. So, in the French interface options will look like "Franc�s / Espa�ol / Vasco" and in the Basque one like "Frantsesa / Gaztelania / Euskara".

We believe that this is not the best way to show language options in a menu. The spanish user that has gone, by chance, to a Basque page, may not recognise so easily that "Gaztelania" is what he/she should choose to return to his/her language version...

So, showing the native name of each language is better for most users. And, in order to get that,
with the other menu, you have the option to choose the names you think more proper in the MessageCatalog


Tip # 5: Display available languages at a given point, as clickable links.

<dtml-in "Localizer.get_languages_map()" mapping>
<dtml-if selected><dtml-var "myMessageCat(title, id)" upper>
<dtml-else><a href="<dtml-var "Localizer.absolute_url()">/changeLanguage?lang=<dtml-var id>"><dtml-var "myMessageCat(title, id)"></a>
</dtml-if>
</dtml-in>

In this case, the language shown appears in uppercase, with no link. The others are clickable links. Through a myMessageCat MessageCatalog you can show your locale names as you like.


Tip # 6: Display the locales available at a given point.

<dtml-in "Localizer.get_available_languages()">
<dtml-var sequence-item>
</dtml-in>

Tip # 7: Display the OTHER locales available at a given point.

First, Create the SELECTED_LANGUAGE variable as described in Tip # 1. Then....

<dtml-in "Localizer.get_available_languages()">
<dtml-unless "_['sequence-item']==SELECTED_LANGUAGE">
<dtml-var sequence-item>
</dtml-unless>
</dtml-in>

Tip # 8: sorry, not in your language

This is a courtesy message that people navigating a site may find polite. They are surfing all the way through German pages when, suddenly, they find some content that has not a German version...

First, create the SELECTED_LANGUAGE variable as described in Tip # 1. Then...

<dtml-in "Localizer.get_languages_map()" mapping>
<dtml-if "id!=SELECTED_LANGUAGE and selected==1">
<dtml-var "myMessageCat('sorry, not in your language')">
</dtml-if>
</dtml-in>

So you can enter different messages for each language, through a MessageCatalog named myMessageCat

The ideal placement for this piece of code is in the default_template (see tip # 2), just below the standard_html_header

Tip # 9: Get a robot parse all your locales for a given page.

If you use Localizer, the different locale versions of a given page have the same URL. You have content at www.foo.com/mypage in 3 languages but a robot, at first glance will only get one... How can you tell the robot there are more pages?

First, Create the SELECTED_LANGUAGE variable as described in Tip # 1
Make sure that in the HEAD of your HTML code, you put a meta tag like:
<meta name="robots" content="INDEX,FOLLOW">

Then, somewhere in the footer or wherever it does not harm anything, include...

<dtml-in "Localizer.get_available_languages()">
<dtml-unless "_['sequence-item']==SELECTED_LANGUAGE">
<a href="<dtml-var "Localizer.absolute_url()[:-10]">/<dtml-var sequence-item>/<dtml-var "absolute_url()[_.len(Localizer.absolute_url())-9:]">"><dtml-var sequence-item></a>
</dtml-unless>
</dtml-in>

This will look best if you hide the text with the same color of its background. If the background of your footer is white and there is a short list of white clickable links like "es en fr" at the footer nobody will notice it, but the robot will follow the links and parse that content also. However, it seems that some robots are prepared to ignore text that appears in the same color of the background, so...

The links will point to www.foo.com/es/mypage, www.foo.com/en/mypage, www.foo.com/fr/mypage ...

Tip # 10: Using local objects

Your language versions may need different localised objects. Different flag gifs, for instance. Or different methods for calculating currencies, or showing date formats...

You do this by creating a LocalFolder object from the "add type" pulldown menu.
Add a LocalFolder and name it myLocalFolder.

Inside of it, add an attribute for each local object that you are going to create. For instance add an attribute named flag_gif and another named attribute localised_date

Then, still inside of myLocalFolder, go to contents and add different objects. Add one different object for each locale/language, naming then according to this convention: flag_gif_xx (like flag_gif_es for Spanish or flag_gif_de for German).

If you add methods instead of images, after you create them you may define some method like localised_date_es as:

<dtml-var "date_posted(fmstr='%d-%m-%Y, %H:%M')">

How to call this local objects from current DTML?

For images, do it like this: <dtml-var "myLocalFolder.flag_gif">

For DTML methods, if they work with any variable, you have to pass the variable on. Like in:
<dtml-var "myLocalFolder.localised_date(date_posted=date_posted)">

If the DTML methods uses no variables, then call it with:
<dtml-var "myLocalFolder.myDTMLmethod(_.None, _)">

Tip # 11: Have 5 locales, need only 2 local objects.

You have 5 language locales in your site (en, es, fr, de, it), yet for a given icon_gif you just need two distinct gifs for 'de' and 'it' and a general one is enough for the other 3 locales.

So, follow the steps described in tip # 10 and inside myLocalFolder add just the two distinct icons icon_gif_de and icon_gif_it. Then, outside myLocalFolder, at the root or wherever it's going to be found, add the general icon for en/es/fr naming it just icon_gif

Call this object with:

<dtml-var "myLocalFolder.icon_gif">

It works.

Tip # 12: Positive discrimination for a given language

Localizer's default settings organize language versions in a fine way. If the user visits www.foo.com he/she will see first the version according to his/her browser's preference. But what if you have a bilingual German/English site and you want all users to have a first glance of the content always in German, even for users with an English browser?

This is the way:

Inside Localizer, create a Python Script named accept_de (for German, as an example)

Add accept_language in the parameter list and then this in the body:

accept_language.set('de', 1.5)

Then, go to the Localizer folder, choose properties, and add accept_de to accept_methods right after accept_path and accept_cookie

The order of elements at the accept_methods parameters is important. It must be: accept_path accept_cookie accept_de

Tip # 13: Rendering DTML through LocalContent objects

This idea derives from this tip at Zopelabs:

First, create a Python Script and call it 'getdtml'. Put this in the parameter list: myString2 = 'whatever'

The script's code:

from Products.PythonScripts.standard import DTML
request = container.REQUEST
RESPONSE = request.RESPONSE
myString = myString2
myDTML = DTML(myString)
return myDTML(context, request, RESPONSE)

Then create a default_template DTML method like this (or a similar one):

<dtml-var standard_html_header>
<h1><dtml-var title></h1>
<dtml-var "getdtml(body)">
<dtml-var standard_html_footer>

There you have it: content you put at the 'body' fields of the LocalContent objects will be rendered as DTML.

Tip # 14: The Method Catalog: Rendering DTML methods through MessageCatalogs

First, create a Python script named 'getdtml' as described in tip #13.

Then, for instance, create a MessageCatalog named 'MethodCatalog' with two languages: 'es' and 'en'.

In a given method or document, for instance in index_html, type as follows:

<dtml-var "getdtml(MethodCatalog('language_header'))">

In the MethodCatalog, search for the string 'language_header' and fill it as you like, for instance:

es: <dtml-var standard_html_header>
en: <dtml-var html_header_with_other_options>

The orthodox way to localize methods is using the LocalFolder object, which is somehow explained in Tip #10. However, this alternate method combining 'getdtml' and 'MethodCatalog' can also be productive. Methods for dates and other locale-sensitive issues can be stored in the MethodCatalog easily.