The current version is 2005-09-22e-1.1.0. You can find
of this technique in my web site, though you cannot modify pages in my site. Please discuss here if you have any comment.
The National Language Support (NLS) feature introduced in this document is not a built-in functionality nor an official plugin of DokuWiki, but an unofficial patch applied to the 2005-09-22e version. A future version of DokuWiki may officially ship another NLS feature which is irrelevant to one described in this document. Please look for plugins or consult Browser Language Detection for more information about NLS in DokuWiki.
The technique introduced in this document is suitable for situations such that:
en.wikipedia.org
or ko.wikipedia.org
according to the translating language as in the WikiPedia.foo
will be translated into three languages A, B, and C, whereas another document bar
will be translated into four languages B, C, D, and E. Furthermore, yet another document baz
will be only in one language, C.The technique in this page works as follows:
In order to use the technique introduced in this document, the following conditions are required:2)
The 'translation flag' is a kind of language code that is appended at the end of page ID, which denotes in what language it is translated. When pageID is the valid ID format (including namespaces) permitted by DokuWiki, the new page ID with a translation flag should be
pageID\.[a-z][a-z](-[a-z][a-z])?
in regular expression.
For example, foo:bar.ko
is a Korean translation whereas foo:bar.en
is an English translation
for the same content.
Because the page ID foo:bar
contains no translation flag,
readers will be redirected to an appropriate translation pages according to their browser setting
if they query this kind of page.
Though they will be redirected basically to the most appropriate one
among existing translations as far as possible,
they will be redirected to a non-existing page if no existing translation matches to their browser's setting.
In other words, readers will not be able to read foo:bar
any more,
therefore the site administrator should append translation flags to all the pages in his/her site
before using this technique.
A method I used and recommend for appending translation flags to pre-existings page is:
foo:bar
is written. → Let's assume that this page is written in zz
language.foo:bar.zz
copying the content of foo:bar
verbatim.foo:bar
.This procedure, of course, is very tedious, but I don't know better way to change page ID's in DokuWiki.
The algorithm is very simple:
foo:bar
) and the reader is not doing indexingko
) matches an existing translation page, redirect the reader to that page (e.g. foo:bar.ko
).foo:bar.{$conf['lang']}
) regardless of whether such page exists or not.DOKU_INC/inc/lang/*
in the DokuWiki installation. (If none matches, choose $conf['lang']
.)$conf['lang']
.That's all.
Please remind again that you should append translation flags to all the page ID's before using this.
Create inc/NLS.php
with the following code
(Administrators can modify two arrays $NLS_locarr
and $NLS_langname
in the first part of this code):
<?php /** * National Language Support (NLS) script for DokuWiki * * @version 2005-09-22e-1.1.0 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author CHA Reeseo <http://www.reeseo.net/> * * Usage: * Include this script into 'doku.php', * between the inclusions of 'inc/pageutils.php' and 'inc/html.php' * * CAUTION: * This script demands a special policy that EVERY page should denote * its own language (.xx or .xx-xx) at the end of its ID. * For example, 'foo:bar.ko' is a page translated into Korean * and 'foo:bar.en' is a page containing the same content in English. * * Quering any page having ID without explicit language notation, * you will be redirected to its appropriate 'localized' page. * ('Unlocalized' page will be invisible.) * * Please rename all the pre-existing pages before applying this script. * * To do: * - Upgrade NLS_locale function */ /* --------------------------------------------------------------- * Configuration options: You can modify or add something to these */ $NLS_locarr['ko'] = 'ko_KR'; $NLS_locarr['en'] = 'en_US'; $NLS_langname['ko'] = '한국어'; $NLS_langname['en'] = 'English'; /* Configuration options end * --------------------------------------------------------------- */ // Setting $ID $ID = getID(); // Redirecting if no language is specified at the end of $ID if (! NLS_pagelang($ID)) { $target = NLS_page4browser($ID); if (! array_key_exists("idx", $_GET) && $_GET['do'] != 'recent') // No redirection when indexing header('Location: ' . wl($target)); } // Resetting $conf['lang'] according to the language setting of user's browser $conf['lang'] = NLS_UI4browser(); // Resetting $lang array @require_once(DOKU_INC.'inc/lang/'.$conf['lang'].'/lang.php'); // Resetting locale setlocale(LC_ALL, NLS_locale($conf['lang'])); /** * Getting locale string * * FIXME: What a poor function this is! */ function NLS_locale($ln = NULL) { global $conf; global $lang; global $NLS_locarr; if (! $ln) $ln = $conf['lang']; $loc = array_key_exists($ln, $NLS_locarr) ? $NLS_locarr[$ln] : $ln; $loc .= '.'; $loc .= array_key_exists('encoding', $lang) ? strtoupper($lang['encoding']) : 'UTF-8'; return $loc; } /** * Printing links to other translations of the given page * (API for template files such as DOKU_TPL/main.php */ function NLS_transmenu($pid = NULL, $delimiter = ",\n", $withself = FALSE) { global $NLS_langname; if (! $pid) { global $ID; $pid = $ID; } $currplang = NLS_pagelang($pid); $tpages = NLS_transpages($pid); if ($currplang && ! $withself) unset($tpages[$currplang]); if ($tpages) { $first = TRUE; foreach ($tpages as $ln => $tid) { $repr = array_key_exists($ln, $NLS_langname) ? $NLS_langname[$ln] : $ln; if (! $first) echo $delimiter; $first = FALSE; if ($currplang == $ln) echo "<em>$repr</em>"; else echo "<a href=\"".wl($tid)."\">$repr</a>"; } } else { echo "None."; } } /** * Selecting a redirection target (page) which best match the browser setting * * Default: page of $conf['lang'] (whether it exists or not) * Choice : among existing translations, highest priority for the browser */ function NLS_page4browser($pid = NULL) { if (! $pid) { global $ID; $pid = $ID; } $blang = NLS_browserlang(); $existing_pages = NLS_transpages($pid); $pid_base = NLS_ID_base($pid); $tmp_page = $pid_base . '.' . $conf['lang']; // default page foreach ($blang as $lang_str => $priority) { $lang_str = str_replace("_", "-", strtolower($lang_str)); if (array_key_exists($lang_str, $existing_pages)) $tmp_page = $pid_base . '.' . $lang_str; elseif (array_key_exists(substr($lang_str, 0, 2), $existing_pages)) $tmp_page = $pid_base . '.' . substr($lang_str, 0, 2); } return $tmp_page; } /** * Selecting a language for UI * * Default: $conf['lang'] * Choice : among existing 'inc/lang/*', highest priority for the browser */ function NLS_UI4browser() { global $conf; $tmp_lang = $conf['lang']; // This ($conf['lang']) is the default! $blang = NLS_browserlang(); foreach ($blang as $lang_str => $priority) { $lang_str = str_replace("_", "-", strtolower($lang_str)); if (is_dir(DOKU_INC . "inc/lang/" . $lang_str)) $tmp_lang = $lang_str; elseif (is_dir(DOKU_INC . "inc/lang/" . substr($lang_str, 0, 2))) $tmp_lang = substr($lang_str, 0, 2); } return $tmp_lang; } /** * Getting a sorted (by priority) array of the languages * from the language setting of the user's web browser */ function NLS_browserlang() { $acclang_arr = split(" *, *", trim($_SERVER['HTTP_ACCEPT_LANGUAGE'])); foreach ($acclang_arr as $acclang) { if (ereg("^(.+) *;.+= *(.+)$", $acclang, $acclang_parts)) $acclang_sorted[$acclang_parts[1]] = (double)($acclang_parts[2]); else $acclang_sorted[$acclang] = 1.0; } asort($acclang_sorted, SORT_NUMERIC); reset($acclang_sorted); return $acclang_sorted; } /** * Getting an associative array (lang => ID) of * all the translated pages for the given page */ function NLS_transpages($pid = NULL) { global $conf; if (! $pid) { global $ID; $pid = $ID; } $transpages = array(); $pid_base_path = $conf['datadir'] . '/' . str_replace(":", "/", NLS_ID_base($pid)); foreach(glob($pid_base_path . ".*.txt") as $fn) { $aid = str_replace("/", ":", substr($fn, strlen($conf['datadir']) + 1, -4)); if ($alang = NLS_pagelang($aid)) { $transpages[$alang] = $aid; } } return $transpages; } /** * Drop language notation (.xx or .xx-xx) from the given ID */ function NLS_ID_base($pid = NULL) { if (! $pid) { global $ID; $pid = $ID; } if (substr($pid, -3, 1) == '.') return substr($pid, 0, -3); elseif (substr($pid, -6, 1) == '.' && substr($pid, -3, 1) == '-') return substr($pid, 0, -6); else return $pid; } /** * Get language (xx, xx-xx, or NULL) from the given ID */ function NLS_pagelang($pid = NULL) { if (! $pid) { global $ID; $pid = $ID; } if (substr($pid, -3, 1) == '.') return substr($pid, -2); elseif (substr($pid, -6, 1) == '.' && substr($pid, -3, 1) == '-') return substr($pid, -5); else return NULL; } ?>
Now, let's add an inclusion of inc/NLS.php
at the beginning part of doku.php
.
The location of this inclusion is very important!
Though NLS script should be loaded as early as possible,
it should be placed after inc/pageutils.php
because NLS script uses it.
Please insert the line of inclusion just after including inc/pageutils.php
(This code shows only the first few lines):
<?php /** * DokuWiki mainscript * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Andreas Gohr <andi@splitbrain.org> */ // xdebug_start_profiling(); if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__)).'/'); require_once(DOKU_INC.'inc/init.php'); require_once(DOKU_INC.'inc/common.php'); require_once(DOKU_INC.'inc/pageutils.php'); require_once(DOKU_INC.'inc/NLS.php'); // insert this line! require_once(DOKU_INC.'inc/html.php'); require_once(DOKU_INC.'inc/auth.php'); require_once(DOKU_INC.'inc/actions.php'); //import variables ...
For the last, let's add a menu for selecting translations to the template
in order for the readers to choose another translations of current page.
Just insert the following code into the main.php
or so in the template you are using:
Other translations of this page: <?php NLS_transmenu(); ?>
NLS_transmenu()
function is an API which generate a menu to the template
and defines following parameters:
NLS_transmenu($pid, $delimiter, $withself)
Each parameter is:
$pid
: The function generate a list of translation of the document which is identified by this variable. The default is DokuWiki's global variable $ID
, that is, the current document.$delimiter
: If there are more than one translations, they will be separated by the delimiter assigned to this variable. The default value is ",\n"
.$withself
: Menu will include the language of the $pid
document itself if the value assigned to this variable is True
, and will exclude it if the value is False
. The default is False
.NLS_locale()
function sucks! An upgrade is seriously needed and it's the final goal of the version 1.1.x series.I like this concept. In reading through the dokuwiki site I see that namespaces are/can also be used. For reference please check multilingual_content and also local.php. At the bottom of the local.php discussion Stéphane Gully shows how he made http://www.pxxo.net/ with french and english translations and graphic language selectors. The end result seems very similar to your site http://www.reeseo.net/home.en.
I would love to see these two approaches merged…
My main concern is the document naming convention. You suggest to add the language code at the end of your page name foo:bar.ko whereas the multilingual discussion suggests the creation of a language namespace at the front end ko:foo:bar.
What are the pro's and con's of these two approaches? - Tito Vergara 12/01/06
I like the present approach better than the multilang. content which adds the “lang:” in a too prominent place (IMHO) - in particular if a sidebar nav.menu (e.g. roundbox..) displays the namespace components as folders. Also since availability of a translation may rather depend on the given page, and some pages might not need translation.
OTOH, I'd like it to be even more discrete and at the same time “intelligent”. What about the following idea:
There are several advantages of the URLs not containing the .LANG : esthetical, portability, readability,…
Setting the $LANG (SESSION or COOKIE or GET) would be done
— MFH, 25.6.07