Tutorial: internationalize a theme
This tutorial is for designers who want their theme in more than one language. You will make every visible text of the design translatable and ship a German translation. Allow one to two hours for a small theme.
Contents
- Step 1: every text through i18n
- Step 2: placeholders, not concatenation
- Step 3: the translation file
- Step 4: tell the siteaccess to read it
- Step 5: dates, numbers and direction
- Step 6: caches and checks
Step 1: every text through i18n
Every text a template prints goes through the i18n operator with a context, a name that groups the texts of one
area. Use design/<your theme>/<area>:
<a class="skip-link" href="#main">'Skip to main content'|i18n( 'design/mytheme/pagelayout' )</a>
<button type="button">'Menu'|i18n( 'design/mytheme/pagelayout' )</button>Also attribute values (title, aria-label, alt of design images, placeholder): wash them when they go into an
attribute, |i18n( ... )|wash. See The i18n operator.
Step 2: placeholders, not concatenation
Word order differs between languages. Put variable parts into the sentence as placeholders:
'Page %current of %total'|i18n( 'design/mytheme/navigator',, hash( '%current', $page, '%total', $pages ) )The second parameter (empty here) is a comment for translators.
Step 3: the translation file
extension/mytheme/translations/ger-DE/translation.ts:
<TS version="2.0" language="ger-DE" sourcelanguage="en">
<context>
<name>design/mytheme/pagelayout</name>
<message>
<source>Skip to main content</source>
<translation>Zum Inhalt springen</translation>
</message>
<message>
<source>Menu</source>
<translation>Menü</translation>
</message>
</context>
<context>
<name>design/mytheme/navigator</name>
<message>
<source>Page %current of %total</source>
<translation>Seite %current von %total</translation>
</message>
</context>
</TS>The starter theme's translations/ger-DE/translation.ts has exactly this form. The source must match the template
text character for character. A text without a translation is shown in English.
Step 4: tell the siteaccess to read it
The kernel reads share/translations/ and the extensions listed in site.ini [RegionalSettings] TranslationExtensions[].
In the extension's siteaccess settings (as the media and starter themes do):
# extension/mytheme/settings/siteaccess/<siteaccess>/site.ini.append.php
[RegionalSettings]
TranslationExtensions[]=mythemeThe siteaccess's [RegionalSettings] Locale (for example ger-DE) chooses the language.
Step 5: dates, numbers and direction
- Dates and numbers through
l10n:{$date|l10n( 'shortdate' )},{$amount|l10n( 'number' )}(Dates, numbers and l10n). langanddiron<html>from$site(Right-to-left designs).- Leave room: German and French texts are often a third longer than English. Buttons and menus must wrap or grow.
Step 6: caches and checks
php bin/php/ezcache.php --clear-id=translation
./console exp:ezchecktranslation ger-DE # statistics for one translation- To do: Open every page type in each language: no English left in the design's own texts.
- To do: Long translations do not break buttons or menus at 375 px.
- To do: The
translation.tsfile is valid XML (xmllint --noout).
Related pages
- Translating template strings
- Translations in a theme
- Translations and languages
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.