Difference between revisions of "Multilingual Support"

From GeeklogWiki
Jump to: navigation, search
(added section on switching locale settings)
(Geeklog 2.2.0 and later)
 
(12 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
The Geeklog language files have been translated into more than 25 languages - but that only means that you can have the user interface in one of those languages. For the actual site content (articles, static pages, ...), there was no support for multiple languages, which means that you either had to have everything in one language only or you ended up with all the different language versions of, e.g. an article, being displayed to anyone.
 
The Geeklog language files have been translated into more than 25 languages - but that only means that you can have the user interface in one of those languages. For the actual site content (articles, static pages, ...), there was no support for multiple languages, which means that you either had to have everything in one language only or you ended up with all the different language versions of, e.g. an article, being displayed to anyone.
  
Euan McKay then came up with a [http://heatherengineering.com/staticpages/index.php/multilingual-en first multi-language hack], which was later [http://www.geeklog.net/forum/viewtopic.php?showtopic=61999 built upon and generalized] by LWC.
+
Euan McKay then came up with a [http://heatherengineering.com/staticpages/index.php/multilingual-en first multilingual hack], which was later [http://www.geeklog.net/forum/viewtopic.php?showtopic=61999 built upon and generalized] by LWC.
  
The multi-language support in Geeklog (as of version 1.4.1) is based on this earlier work by Euan and LWC.
+
The multilingual support in Geeklog (as of version 1.4.1) is based on this earlier work by Euan and LWC.
  
  
 
== How it works ==
 
== How it works ==
  
The basic idea behind the multi-language support is to encode the language of an object into its ID. For example, for a story to encode it into the story ID, like so:
+
The basic idea behind the multilingual support is to encode the language of an object into its ID. For example, for a story to encode it into the story ID, like so:
  
 
<pre>http://www.example.com/article.php/introduction_en -- English version
 
<pre>http://www.example.com/article.php/introduction_en -- English version
Line 20: Line 20:
 
== Setting it up ==
 
== Setting it up ==
  
In config.php, there is a new section to enable multi-language support and to define the list of supported languages:
+
=== Geeklog 1.4.1 ===
  
<pre>// Multi-language support
+
In config.php, there is a new section to enable multilingual support and to define the list of supported languages:
 +
 
 +
<pre>// Multilingual support
 
// (note that this section is commented out - remove the '/*' and '*/' lines
 
// (note that this section is commented out - remove the '/*' and '*/' lines
 
//  below to activate it and make sure you understand what it does)
 
//  below to activate it and make sure you understand what it does)
Line 33: Line 35:
 
// 3) All shortcuts must have the same length, e.g. 2 characters.
 
// 3) All shortcuts must have the same length, e.g. 2 characters.
  
// The shortcuts are to be used in IDs of objects that are multi-language
+
// The shortcuts are to be used in IDs of objects that are multilingual
 
// aware, e.g. /article.php/introduction_en and /article.php/introduction_de
 
// aware, e.g. /article.php/introduction_en and /article.php/introduction_de
 
// for the English and German version of an introductory article.
 
// for the English and German version of an introductory article.
Line 54: Line 56:
 
*/</pre>
 
*/</pre>
  
To enable multi-language support, the two arrays $_CONF['language_files'] and $_CONF['languages'] have to be defined. In the default config.php, they are commented out and, therefore, not defined.
+
To enable multilingual support, the two arrays $_CONF['language_files'] and $_CONF['languages'] have to be defined. In the default config.php, they are commented out and, therefore, not defined.
 +
 
 +
=== Geeklog 1.5.0 and later ===
 +
 
 +
As of Geeklog 1.5.0, the <tt>config.php</tt> file has been replaced with a web-based configuration that can be found under "Configuration" in the Admin's block. Under the "Languages and Locale" heading, you'll find two options:
 +
* Language Files
 +
* Languages
 +
These two options are the equivalents of the <code>$_CONF['language_files']</code> and <code>$_CONF['languages']</code> arrays, as explained above. To use the multilingual feature, '''both''' of these options have to be enabled. Other than that, the two options work as described above.
 +
 
 +
Note that in Geeklog 1.5.0, you can not easily disable multilingual support again (for a workaround, see [http://www.geeklog.net/forum/viewtopic.php?showtopic=83327 here]). As of Geeklog 1.5.1, there is a litte <tt>(X)</tt> next to the options (once they're enabled). Click on the <tt>(X)</tt> to disable the options again (remember that you need to disable both of them).
 +
 
 +
=== Geeklog 2.2.0 and later ===
 +
 
 +
As of Geeklog 2.2.0 multi-language items of plugins (like Staticpages), articles and topics are fully supported. No more guess work is involved by just parsing the URL for a language code, which may just be part of an id and not an actual code. This update supports normal, rewrite, and routing URLs.
 +
 
 +
This means an anonymous user directly visiting a muti language page will see the page in the language code specified in the item id. Users using the switch language block will see the item in the new language as long as the id exists for the new language. Switch Language block also uses switchlang_homepage config option if enabled and item doesn't exist in language will return to homepage else a 404 error is displayed.
 +
 
 +
Plugins now need to register a core hidden config option langurl_pluginname to support multi-language items. This config option will store an array with the follow information about the url that supports multiple languages:
 +
 
 +
directory, filename, URL variable name of Id
 +
 
 +
Also required to support PLG_getItemInfo (which calls plugin_getiteminfo_pluginname) that can return if the Id exists or not of the item.
  
 +
Plugin Developers see function _getLanguageInfoFromURL in lib-common for more information (which replaced COM_getLanguageFromURL).
  
 
=== The shortcuts ===
 
=== The shortcuts ===
  
For each of the languages you intend to support, you will have to define a shortcut that will then be used in the IDs of the multi-language objects, as explained above.
+
For each of the languages you intend to support, you will have to define a shortcut that will then be used in the IDs of the multilingual objects, as explained above.
  
 
You can freely define these shortcuts, but it would make sense to set them in some relation to the language which they represent. From Geeklog's point of view, though, it doesn't matter whether the English language is represented by a shortcut 'en' or by 'peter'.
 
You can freely define these shortcuts, but it would make sense to set them in some relation to the language which they represent. From Geeklog's point of view, though, it doesn't matter whether the English language is represented by a shortcut 'en' or by 'peter'.
Line 84: Line 108:
 
Most of the time, you'll want to use the native names of the languages, e.g. "Deutsch" instead of "German", but that's only a convention.
 
Most of the time, you'll want to use the native names of the languages, e.g. "Deutsch" instead of "German", but that's only a convention.
  
 +
 +
== Blocks ==
 +
 +
Multilingual blocks are only supported as of Geeklog 1.5.1. The setup differs slightly from the setup for stories, topics, etc.
 +
 +
Let's assume you want to create a multilingual "about this site" block and that your site is configured for two languages (say, English and German). For this setup you would then need ''three''(!) blocks. The block name serves as the ID and you would create blocks with the following names:
 +
* about_en (disabled)
 +
* about_de (disabled)
 +
* about
 +
The first two blocks would simply contain your content in English and German, respectively. Both blocks should be ''disabled''. The third block then serves as a placeholder for the actual block for the current language. Therefore, only this block ("about", in our example) should be enabled. When the multilingual support is enabled, you will never see the contents of that block, as it will be replaced with the proper block for the current language, e.g. "about_en" for English.
  
 
== Switching languages ==
 
== Switching languages ==
Line 99: Line 133:
 
== Detecting the language ==
 
== Detecting the language ==
  
When a user comes to a multi-language enabled site, Geeklog will check for the user's preference setting first (if it's a registered user), then for the language cookie, and if that couldn't be found, it tries to get the language from the browser's 'Accept-Language' header (which only works if you chose to use the ISO shortcuts, as explained above). If all else fails, content will be presented in the site's default language, i.e. $_CONF['language'].
+
When a user comes to a multilingual enabled site, Geeklog will check for the user's preference setting first (if it's a registered user), then for the language cookie, and if that couldn't be found, it tries to get the language from the browser's 'Accept-Language' header (which only works if you chose to use the ISO shortcuts, as explained above). If all else fails, content will be presented in the site's default language, i.e. $_CONF['language'].
  
  
Line 108: Line 142:
 
If you have a list of objects under your plugin's control and only want to show the objects in the current language, you can use the COM_getLangSQL() function when building your SQL request. It will provide the part of an SQL request to only return the objects in the current language (see the function's description in lib-common.php for details).
 
If you have a list of objects under your plugin's control and only want to show the objects in the current language, you can use the COM_getLangSQL() function when building your SQL request. It will provide the part of an SQL request to only return the objects in the current language (see the function's description in lib-common.php for details).
  
COM_getLangSQL() will return an empty string when multi-language support is disabled, so you don't need to check for that yourself.
+
COM_getLangSQL() will return an empty string when multilingual support is disabled, so you don't need to check for that yourself.
  
 
Most of the time, that should be all that you need to know about supporting multiple languages in a plugin. In some scenarios, the following functions may also come in handy:
 
Most of the time, that should be all that you need to know about supporting multiple languages in a plugin. In some scenarios, the following functions may also come in handy:
Line 133: Line 167:
 
$_CONF['locale_de'] = 'de_DE';</pre>
 
$_CONF['locale_de'] = 'de_DE';</pre>
  
You can switch all of the following [http://www.geeklog.net/docs/config.html#locale locale settings] as described above:
+
You can switch all of the following [http://www.geeklog.net/docs/english/config.html#languages_locale locale settings] as described above:
 
* <code>$_CONF['locale']</code>
 
* <code>$_CONF['locale']</code>
 
* <code>$_CONF['date']</code>
 
* <code>$_CONF['date']</code>
Line 144: Line 178:
 
* <code>$_CONF['thousand_separator']</code>
 
* <code>$_CONF['thousand_separator']</code>
 
* <code>$_CONF['decimal_separator']</code>
 
* <code>$_CONF['decimal_separator']</code>
 +
 +
 +
'''Note:''' In Geeklog 1.5.0 and later, you will have to add the language-specific entries ($_CONF['date_de'], etc.) to the <tt>siteconfig.php</tt> file. The settings for the default language can be found in the Configuration admin panel:
 +
 +
: Configuration > Geeklog > Languages and Locale
  
  
Line 149: Line 188:
  
 
* To make things nicer for the user, the language could be hidden from the ID when editing objects. Instead, the user could be presented with a drop-down menu of the available languages. The shortcut could then be silently added to the ID when the object is saved.
 
* To make things nicer for the user, the language could be hidden from the ID when editing objects. Instead, the user could be presented with a drop-down menu of the available languages. The shortcut could then be silently added to the ID when the object is saved.
* [http://project.geeklog.net/tracker/index.php?func=detail&aid=634&group_id=6&atid=108 Feature Request]: Make it easier to make a copy of an article for translation.
+
* [[SoC improve multilingual feature|More ideas]]

Latest revision as of 15:05, 11 December 2017

Background

The Geeklog language files have been translated into more than 25 languages - but that only means that you can have the user interface in one of those languages. For the actual site content (articles, static pages, ...), there was no support for multiple languages, which means that you either had to have everything in one language only or you ended up with all the different language versions of, e.g. an article, being displayed to anyone.

Euan McKay then came up with a first multilingual hack, which was later built upon and generalized by LWC.

The multilingual support in Geeklog (as of version 1.4.1) is based on this earlier work by Euan and LWC.


How it works

The basic idea behind the multilingual support is to encode the language of an object into its ID. For example, for a story to encode it into the story ID, like so:

http://www.example.com/article.php/introduction_en -- English version
http://www.example.com/article.php/introduction_de -- German version

Now there is a way to identify the language of an object (article, topic, static page, ...) and it can be displayed (or not), based on the user's language preferences. It's also possible then to switch between the various languages in which an object exists in the database.


Setting it up

Geeklog 1.4.1

In config.php, there is a new section to enable multilingual support and to define the list of supported languages:

// Multilingual support
// (note that this section is commented out - remove the '/*' and '*/' lines
//  below to activate it and make sure you understand what it does)
/*

// IMPORTANT!
// 1) Both the $_CONF['language_files'] and the $_CONF['languages'] arrays
//    (see below) must have the same number of elements.
// 2) The shortcuts used must be the same in both arrays.
// 3) All shortcuts must have the same length, e.g. 2 characters.

// The shortcuts are to be used in IDs of objects that are multilingual
// aware, e.g. /article.php/introduction_en and /article.php/introduction_de
// for the English and German version of an introductory article.

// Supported languages
// Maps a shortcut to a Geeklog language file (without the '.php' extension)
$_CONF['language_files'] = array (
    'en' => 'english',
    'de' => 'german_formal'
);

// Display names of supported languages
// Maps the same shortcuts as above to a language name. The language names
// are used to let users switch languages, e.g. in a drop-down menu.
$_CONF['languages'] = array (
    'en' => 'English',
    'de' => 'Deutsch'
);

*/

To enable multilingual support, the two arrays $_CONF['language_files'] and $_CONF['languages'] have to be defined. In the default config.php, they are commented out and, therefore, not defined.

Geeklog 1.5.0 and later

As of Geeklog 1.5.0, the config.php file has been replaced with a web-based configuration that can be found under "Configuration" in the Admin's block. Under the "Languages and Locale" heading, you'll find two options:

  • Language Files
  • Languages

These two options are the equivalents of the $_CONF['language_files'] and $_CONF['languages'] arrays, as explained above. To use the multilingual feature, both of these options have to be enabled. Other than that, the two options work as described above.

Note that in Geeklog 1.5.0, you can not easily disable multilingual support again (for a workaround, see here). As of Geeklog 1.5.1, there is a litte (X) next to the options (once they're enabled). Click on the (X) to disable the options again (remember that you need to disable both of them).

Geeklog 2.2.0 and later

As of Geeklog 2.2.0 multi-language items of plugins (like Staticpages), articles and topics are fully supported. No more guess work is involved by just parsing the URL for a language code, which may just be part of an id and not an actual code. This update supports normal, rewrite, and routing URLs.

This means an anonymous user directly visiting a muti language page will see the page in the language code specified in the item id. Users using the switch language block will see the item in the new language as long as the id exists for the new language. Switch Language block also uses switchlang_homepage config option if enabled and item doesn't exist in language will return to homepage else a 404 error is displayed.

Plugins now need to register a core hidden config option langurl_pluginname to support multi-language items. This config option will store an array with the follow information about the url that supports multiple languages:

directory, filename, URL variable name of Id

Also required to support PLG_getItemInfo (which calls plugin_getiteminfo_pluginname) that can return if the Id exists or not of the item.

Plugin Developers see function _getLanguageInfoFromURL in lib-common for more information (which replaced COM_getLanguageFromURL).

The shortcuts

For each of the languages you intend to support, you will have to define a shortcut that will then be used in the IDs of the multilingual objects, as explained above.

You can freely define these shortcuts, but it would make sense to set them in some relation to the language which they represent. From Geeklog's point of view, though, it doesn't matter whether the English language is represented by a shortcut 'en' or by 'peter'.

Please note:

  • All the shortcuts in both of the arrays have to be of the same length.
  • The shortcut must be appended to the end of an object's ID and it must be preceded by an underscore '_' character.
  • It's recommended that you use a language's ISO abbreviation ('en' for English, 'de' for German, etc.), either with or without the country appendix ('en-US'), as Geeklog will also try to determine a user's preferred language from their browser setting.


The language files

The $_CONF['language_files'] array defines which language files should represent which language. Note that Geeklog also uses the language file name for a user's language setting (in their preferences).

It's recommended that you remove all the other language files, i.e. those for which you do not intend to have content in that particular language on your site.

Note: Be careful when mixing languages that use different character sets (e.g. Russian and Japanese). You may want to switch to the UTF-8 versions of all language files for such a setup.


The language names

The $_CONF['languages'] array defines a set of display names for the supported languages. These names are used to let the user switch between the supported languages, e.g. from a drop-down menu.

Most of the time, you'll want to use the native names of the languages, e.g. "Deutsch" instead of "German", but that's only a convention.


Blocks

Multilingual blocks are only supported as of Geeklog 1.5.1. The setup differs slightly from the setup for stories, topics, etc.

Let's assume you want to create a multilingual "about this site" block and that your site is configured for two languages (say, English and German). For this setup you would then need three(!) blocks. The block name serves as the ID and you would create blocks with the following names:

  • about_en (disabled)
  • about_de (disabled)
  • about

The first two blocks would simply contain your content in English and German, respectively. Both blocks should be disabled. The third block then serves as a placeholder for the actual block for the current language. Therefore, only this block ("about", in our example) should be enabled. When the multilingual support is enabled, you will never see the contents of that block, as it will be replaced with the proper block for the current language, e.g. "about_en" for English.

Switching languages

Registered users can always switch their preferred language by selecting another language in their preferences.

To make things more convenient (and also allow anonymous users to switch the language), you can put a PHP block on your site. Geeklog provides a function phpblock_switch_language that will display a drop-down menu of all available languages (if you only have two languages defined, it will display a simple link to the other language instead).

This function can also be called from the header.thtml template file of your theme, so that you can put it into your site's menu:

<?php print phpblock_switch_language(); ?>

Technically, switching the language will set a cookie (with the selected language) and also update a user's language preference, if they're registered with the site.


Detecting the language

When a user comes to a multilingual enabled site, Geeklog will check for the user's preference setting first (if it's a registered user), then for the language cookie, and if that couldn't be found, it tries to get the language from the browser's 'Accept-Language' header (which only works if you chose to use the ISO shortcuts, as explained above). If all else fails, content will be presented in the site's default language, i.e. $_CONF['language'].


Supporting multiple languages

Developers of plugins and other add-ons don't have to do much to support multiple languages. Mainly, the objects under your plugin's control will have to have an editable, non-numerical ID (like Geeklog's stories have), so that the language shortcut can be appended to the ID.

If you have a list of objects under your plugin's control and only want to show the objects in the current language, you can use the COM_getLangSQL() function when building your SQL request. It will provide the part of an SQL request to only return the objects in the current language (see the function's description in lib-common.php for details).

COM_getLangSQL() will return an empty string when multilingual support is disabled, so you don't need to check for that yourself.

Most of the time, that should be all that you need to know about supporting multiple languages in a plugin. In some scenarios, the following functions may also come in handy:

  • COM_getLanguageId returns the shortcut of the current user's language
  • COM_getLanguage returns the full name of the current user's language, i.e. the name of the Geeklog language file (without the .php extension)


Switching locale settings

Switching the language will often also require different formatting of the date, time, and other locale settings. For this, you can define alternative settings for each language in your site's config.php.

For example, the default date formatting in Geeklog's config.php is

$_CONF['date'] = '%A, %B %d %Y @ %I:%M %p %Z';

which, amongst other things, includes a time format using am/pm. If your site switches between, say, English and German, then your typical German visitor will expect the time to use a 24-hour format, e.g.

$_CONF['date'] = '%A, %d. %B %Y, %R Uhr';

If you're using the ISO abbreviation 'de' for German, then you could have the following in your site's config.php:

$_CONF['date'] = '%A, %B %d %Y @ %I:%M %p %Z';
$_CONF['date_de'] = '%A, %d. %B %Y, %R Uhr';

With these two lines, Geeklog would use the 'date_de' formatting when displaying content in German, and the 'date' formatting for all the other languages.

Actually, for this to work properly, you will also have to set $_CONF['locale'] and $_CONF['locale_de'] accordingly, since some of the date formatting (localized day and month names) requires the correct locale to be set:

$_CONF['locale'] = 'en_GB';
$_CONF['locale_de'] = 'de_DE';

You can switch all of the following locale settings as described above:

  • $_CONF['locale']
  • $_CONF['date']
  • $_CONF['daytime']
  • $_CONF['shortdate']
  • $_CONF['dateonly']
  • $_CONF['timeonly']
  • $_CONF['week_start']
  • $_CONF['hour_mode']
  • $_CONF['thousand_separator']
  • $_CONF['decimal_separator']


Note: In Geeklog 1.5.0 and later, you will have to add the language-specific entries ($_CONF['date_de'], etc.) to the siteconfig.php file. The settings for the default language can be found in the Configuration admin panel:

Configuration > Geeklog > Languages and Locale


Notes and ideas

  • To make things nicer for the user, the language could be hidden from the ID when editing objects. Instead, the user could be presented with a drop-down menu of the available languages. The shortcut could then be silently added to the ID when the object is saved.
  • More ideas