JUCI is written with multi-language support from the start. Translations are added through a combination of special directives and a translation database.
All text strings that need to be translated are first tagged using any one of these methods:
In code, strings are tagged using the gettext
method (which does not do
anything - it is an empty method that is there just for easy parsing of the
strings), and they are translated using $tr() juci service. This is why you
typically write $tr(gettext(...))
.
When you write your code, you should try to make sure that you only ever translate static strings. So do no write {{variable|translate}}. This should be avoided because it will only work if variable actually contains translatable text. If it does not, then it will not work obviously and the string extracting process has no way of knowing in advance what value the variable can have. So instead, use a lookup table of translatable strings if you do want to look up a string based on a variable.
The strings are extracted from all js and html files during the build process.
The makefile will run angular-gettext
job through grunt
and extract them. It
will put them into the po files folder in a sisngle file called juci_all_strings.pot
po/
|-- custom.js
|-- de.po
|-- en.po
|-- fi.po
|-- juci_all_strings.pot
|-- sv.po
|-- titles.js
You can add custom strings to the database by simply tagging them using
gettext(...)
. Normally you would do this exactly in the place where the string
is to be used. In html you will use translate directive and in code you will
tag them with gettext
and typically also translate them. If, however, you have
strings that you still want to translate but which can not be put anywhere
else, then you can put them in a separate javascript file in your plugin which
you will with lines just enclosing strings in gettext
function call:
gettext("foo")
gettext("bar")
Dynamic data is often problematic. What you can do though is use String.format and then tag the static format string to be included in the database. You will then translate a format string with tags in it to different languages. Like this:
String.format($tr(gettext("There were {1} people in the room")),
person_count);
This one is harded. You still need to know the full domain of strings to be
translated - this is unavoidable. What you would do then is put your language
tables into a json file and compile it into a js translation file that you will
load on top of main translation using a script provided by juci called
./scripts/json-to-lang-js
. You then put this file into /www/ folder and run
juci-update
to regenerate index.html so that it includes this file as well.
The makefile will also include menu titles and autogenerated page title keys into the database so that you can translate them as well. Page title keys will have the form of dotted page filename with .title appended after it. So internet-settings page title key will be called internet.settings.title.
What you end up with after you build juci is a single file that contains all
strings from all plugins included in the build. poedit
is then used to
translate this file into different languages. You fire up poedit, create a new
database (if your language does not already exist) and choose Catalog ->
Update from POT. And then you translate the strings and save the .po file in
po/ folder. When you then run make, your translation databse will be rebuild
with new strings and put into /www/99-translations.js in the final package.
If you already have a language file from before, you can open it with poedit
and update it from the new .pot file. Poedit will then hide strings that are no
longer used and add new ones.
To set default language and list of translations you currently need to add it in your /etc/config/juci file.
config localization localization
option default_language 'en'
list languages 'en'
list languages 'se'
Note: if you have selected a language on the web page and then set default language, next time you load the page you will still get the language that you have selected. This is because juci saves the language in your browser localStorage and loads it when you visit the site. If the value is not present in your localStorage, you will get the default_language setting selected instead.