Creating Translations

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:

  • translate directive: <div translate>Text to be translated</div>
  • angular filter: {{'text string'|translate}}
  • or directly in code: $tr(gettext("text string))

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.

Where do the strings end up?

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") 

Handling dynamic strings

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); 

Wheat about dynamic data in configs?

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.

What other things are included in the database?

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.

Translating the po template (.POT)

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.

Configuring available translations in JUCI

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.