Internationalization
Overview
The bigger your web service is, the more attention you should pay to make it more accessible to other users. One of the main barriers is language. Because of the MVC model we split the application into logic, behavior and view, but there is sometimes a need for a another partition.
In creating a multi-lingual service, you only need to focus on changing the content you want to display - the view will always remain the same. e_lang provides a very convenient API to keep the same views and only switch the dictionary the application uses for each request.
e_lang has been built upon key-value mapping. The basic idea is to use only the keys in your application instead of language-specific elements and place all of the translations in the separate files.
The keys for translation used within your application are strings, which can be parsed in two different ways:
string contains : - string is split by : character and the actual key is a tuple of string - tokens created by splitting the original string
string does not contain : - string is the key itself
The language files are read into memory during the start of the application, so after any change in those files there is a need to reload them. It can be done by calling:
e_lang:reinstall().
Defining translations
Preparing project.conf
The first step of the translating process is to put the language files tuple in project.conf file. This two-element tuple should be in the following format:
{language files, [LanguageFileSpec]}.where
LanguageFileSpec = {LangCode, PathToTranslationFile}
LangCode = atom()
PathToTranslationFile = string()
Preparing translation files
Secondly, create all files specified in project.conf and place their translations for all the keys used in the application.
The translation file contains Erlang tuples in the format: {Key, Translation} where Key is either a single string or a tuple of strings (look at Overview section).
Translating
There are three ways of accessing translated strings:
We can use <wpart:lang key=Key /> inside the html file. During the process of tags expanding, this tag will be replaced with the proper translation.
Call wpart_lang:get_translation with the key to translate.
Use tuple {key, Key} in the description option in .hrl record definition file.
Control flow
All types of translating (using wpart, specifying the description in .hrl files and explicitly calling the get translation function) has the same control flow.
The target language is chosen in the following order:
from lang key kept in session in e_dict
from default_language option in project.conf file
if none of the previous options are set, e_lang sets the default language to English (en language code)
Language codes used in application must be the same as those declared in project.conf.
The translation process behaves as follows:
- if the translation for the given key is found, it is returned
- otherwise, if the key is a single string (not a tuple), the key is returned
in all other cases, the "no translation found" string is returned
Example
html embedding
1 ...
2 <h1><wpart:lang key="contact:header"/></h1>
3 erlangweb@example.org<br/>
4 <wpart:lang key="back"/>
5 ...
In this example two translations will be used: one with the key {"contact", "header"} and one with back.
get_translation_call
1 ...
2 ErrorMsg = wpart_lang:get_translation("errors:no_such_login"),
3 ...
ErrorMsg variable will be bound to the translation corresponding to the {"errors", "no_such_login"} key.
description option in record definition file
1 ...
2 -record(login_types,
3 {login = {string, [{description, {key, "login:login"}}]},
4 password = {password, [{description, {key, "login:password"}}]}}).
5 ...
Descriptions for #login_types.login and #login_types.password will be found under the keys {"login", "login"} and {"login", "password"} respectively.
language configuration file: en.conf
1 {{"contact", "header"}, "My contact details"}.
2 {"back", "Go Back"}.
3 {{"errors", "no_such_login"}, "There is no such user in the system"}.
4 {{"login", "login"}, "Login"}.
5 {{"login", "password"}, "Password"}.
This file includes all the translations for the examples quoted above.
