Internationalization (i18n)
i18n makes page content multilingual without duplicating the page: the markup key inserts the current language's text in place — from a CSV table, from a setting, or straight out of the markup. It is meant for authors who keep menus, buttons and building blocks in several languages, and for template developers who need the same texts from PHP.
Getting started
Quick start: show a text in two languages – the shortest path to a first result, in three steps.
Create the translation table → place the markup on a page → check which language is chosen
Common tasks
| What you want | For whom | Where you do it | Instructions |
|---|---|---|---|
| insert a translated text | authors | markup key | Translation key |
| write a translation without a table | authors | markup with language pairs | Inline translation |
| force a text into a fixed language | authors | markup with a language code | Fixed language |
| show a configuration value | authors | markup that points at a setting | Configuration value |
| maintain your translations | authors | the CSV table | CSV format |
| understand which language is chosen | everyone | – | Language detection |
| use the same texts from PHP | developers | – | Using it in templates |
What it does
The wki18n plugin brings four sources of multilingual text into a page:
- Translation keys – looked up in a CSV table
- Inline translations –
de:Text|en:Text, written into the markup itself - Configuration values – DokuWiki settings, with language pairs resolved
- Template values – template settings, resolved the same way
When to use it
- Multilingual navigation – menu labels that follow the reader's language
- Translatable interface elements – buttons, labels, hints
- Template integration – sidebar, footer, header
- One place for shared texts – every recurring label in a single table
Syntax
Translation key
Home Contact
Looks the key up in the translation table (see CSV format) for the current language.
Fixed language
Startseite Home
Uses the named language, whatever the page or the browser asks for.
Inline translation
de:Ja|en:Yes|sl:Da de:Speichern|en:Save|sl:Shrani
The translations live in the markup; no table is involved.
Configuration value
conf:title conf:tagline
Reads a DokuWiki setting and resolves the language pairs in it.
Template setting
tpl:footerText tpl:topSidebarTitle
Reads a template setting and resolves the language pairs in it.
CSV format
Your own translations belong in data/wki18n/i18n.csv (strictly: <savedir>/wki18n/i18n.csv). That file lives outside the plugin folder, survives every update, and is never served by the web server:
key,de,en,sl menu_home,Startseite,Home,Domov menu_contact,Kontakt,Contact,Kontakt button_save,Speichern,Save,Shrani
The plugin itself ships only a few general keys in lib/plugins/wki18n/i18n.csv (menu_home, menu_contact, menu_back), and every install replaces that file. Your table is read after it and wins per key and per language: a row in your table overrides the shipped value in every language it fills in, and an empty cell leaves the shipped value in place. A line that starts with # is a comment.
| Column | Meaning |
|---|---|
key | a unique key |
de | the German text |
en | the English text |
| … | further languages |
Language detection
The language is determined in this order (helper.php, detectLanguage()):
- The visitor's explicit choice –
?lang=slin the request, otherwise the choice remembered from an earlier request (a cookie). It only applies after a deliberate click in a language switcher; a visitor who never chooses never notices it. - The namespace path –
de:start→ de - The language of the window that opened this one – a window such as the media dialog keeps the language it was opened in; this is not remembered
- The browser header –
Accept-Language: de-DE→ de - DokuWiki's language –
$conf['lang'] - The plugin default – the
defaultLangsetting
Each candidate is checked against the languages list; a code that is not on it is skipped.
Configuration
| Option | Default | Description |
|---|---|---|
enabled | 1 | turns the plugin on |
languages | de,en,sl,it,hr | the languages you serve |
defaultLang | en | the fallback language |
langPosition | 0 | where the language sits in the namespace (0 = first level) |
The default is the value the plugin ships with. On this site, languages is set to de,en,sl.
Examples
Example 1: navigation
===== menu_navigation ===== * [[..:start|Home]] * [[..:docs:index|Project Documentation]] * [[..:contact|Contact]]
Result (browser set to English):
- Home
- Project Documentation
- Contact
Example 2: inline text on a button
<button>de:Absenden|en:Submit|sl:Pošlji</button>
Example 3: footer from a template setting
<footer> tpl:footerText </footer>
Example 4: a fixed language for language links
Languages: [[..:de:start|Startseite]] |
[[..:en:start|Home]] |
[[..:sl:start|Domov]]
Result:
- Languages: Startseite | Home | Domov
Using it in templates
From PHP
<?php // Load the helper $helper = plugin_load('helper', 'wki18n'); if ($helper) { // A translation for the current language echo hsc($helper->get('menu_home')); // A fixed language echo hsc($helper->get('menu_home', 'en')); // Resolve an inline value echo hsc($helper->parseMultilang('de:Ja|en:Yes')); // A template setting echo hsc($helper->getTplConfig('footerText')); } ?>
Migrating from wvdslang
Search and replace
Old: {{wk:lang>
New: {{wk:i18n>
Old: {{wk:lang:
New: {{wk:i18n:
Release notes
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-01-29 | first release (successor of wvdslang) |
See also
Technical reference
Class: syntax_plugin_wki18n
File: lib/plugins/wki18n/syntax.php
| Method | Description |
|---|---|
getType() | returns substition (the DokuWiki core spells the mode this way) |
getSort() | returns 1 – ahead of internalmedia (320), so ... is not read as a media link |
connectTo($mode) | registers the i18n patterns |
handle($match, …) | parses the markup and extracts its content |
render($mode, …) | outputs the translated text |
Class: helper_plugin_wki18n
File: lib/plugins/wki18n/helper.php
| Method | Description |
|---|---|
get($key, $lang) | returns the translation for a key |
parseMultilang($value, $lang) | resolves the de:X|en:Y format |
getConfig($key, $lang) | returns a DokuWiki setting, resolved |
getTplConfig($key, $lang) | returns a template setting, resolved |
detectLanguage() | determines the current language |
getLanguages() | returns the configured languages |
getContentDir() | returns the directory of your own translation table, <savedir>/wki18n |
<wk:audit stack=“doku” title=“wki18n Plugin”>
<wk:include ref="code:qualitaet" critical="true">[x][x][x][x]</wk:include> <wk:include ref="stacks:dokuwiki-php">[x][x][x][x][x]</wk:include> <wk:include ref="sicherheit:kritis" critical="true">[x][x][x][x][x]</wk:include>
</wk:audit>
DISCUSSION
Package details
Plugin: wki18n
Version: 1.0.0
Namespace: lib/plugins/wki18n/
Author: Wolfgang van der Stille Wolfgang.van.der.Stille@gmail.com (The White Knight Labs)
License: GPL 2
wvdslang plugin.
Redirects moved to the wvdscond plugin (separation of concerns).