Difference between revisions of "Multilingual Support"
(Added section on how to support multiple languages in plugins) |
(→Geeklog 2.2.0 and later) |
||
(15 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | |||
− | |||
== Background == | == 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. | 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 | + | 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 | + | 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 | + | 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 22: | Line 20: | ||
== Setting it up == | == Setting it up == | ||
− | + | === Geeklog 1.4.1 === | |
− | <pre>// | + | 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 35: | 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 | + | // 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 56: | Line 56: | ||
*/</pre> | */</pre> | ||
− | To enable | + | 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 | + | 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 86: | 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 101: | Line 133: | ||
== Detecting the language == | == Detecting the language == | ||
− | When a user comes to a | + | 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 110: | 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 | + | 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: | ||
* COM_getLanguageId returns the shortcut of the current user's language | * 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) | * 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 | ||
+ | <pre>$_CONF['date'] = '%A, %B %d %Y @ %I:%M %p %Z';</pre> | ||
+ | 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. | ||
+ | <pre>$_CONF['date'] = '%A, %d. %B %Y, %R Uhr';</pre> | ||
+ | |||
+ | If you're using the ISO abbreviation 'de' for German, then you could have the following in your site's config.php: | ||
+ | <pre>$_CONF['date'] = '%A, %B %d %Y @ %I:%M %p %Z'; | ||
+ | $_CONF['date_de'] = '%A, %d. %B %Y, %R Uhr';</pre> | ||
+ | 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 <code>$_CONF['locale']</code> and <code>$_CONF['locale_de']</code> accordingly, since some of the date formatting (localized day and month names) requires the correct locale to be set: | ||
+ | <pre>$_CONF['locale'] = 'en_GB'; | ||
+ | $_CONF['locale_de'] = 'de_DE';</pre> | ||
+ | |||
+ | 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['date']</code> | ||
+ | * <code>$_CONF['daytime']</code> | ||
+ | * <code>$_CONF['shortdate']</code> | ||
+ | * <code>$_CONF['dateonly']</code> | ||
+ | * <code>$_CONF['timeonly']</code> | ||
+ | * <code>$_CONF['week_start']</code> | ||
+ | * <code>$_CONF['hour_mode']</code> | ||
+ | * <code>$_CONF['thousand_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 120: | 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. | ||
+ | * [[SoC improve multilingual feature|More ideas]] |
Latest revision as of 15:05, 11 December 2017
Contents
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