Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: fa74e470e2
Fetching contributors…

Cannot retrieve contributors at this time

251 lines (183 sloc) 7.918 kb
-*- html -*-
Erlang gettext overview page
@title Erlang Gettext tools for multi-lingual capabilities
@author Torbjörn Törnkvist <tobbe@tornkvist.org>
@copyright 2003-2011 Törbjorn Törnkvist
@version {@version}, {@date} {@time}
@doc The 'gettext' application makes it possible to internationalize
your application. For example, if you have a Web application
where you want to present information in different languages,
you can accomplish that with the 'gettext' application.
== Introduction ==
The name 'gettext' comes from the GNU package with the same name.
However, the only thing they have in common is the format
of the PO-files, i.e the files containing the text that can
be translated. A PO file contains the 'Original String'
and the 'Translated String'.
Example of an entry generated by 'gettext':
<pre>
#: esmb_gettext.erl:13
msgid ""
"Hello, World!"
msgstr ""
"Hej, V&#228;rlden!"
</pre>
The string(s) following the 'msgid' tag is the Key,
i.e the 'Original String'. The string(s) following the
'msgstr' tag is the Value, i.e the 'Translated String'
that will be presented in place of the 'Original String'.
Using 'gettext' you can create an initial PO-file containing
all the strings of your application that should be possible
to translate. By translating the strings into some other
language and loading the new PO-file into the 'gettext'
DB you can adapt your application for different languages.
NOTE: The very first entry of the PO file is a bit special
since it contains meta-information. Especially important
is the 'charset' information. It is important that you
set this right when doing a translation. If you store
the strings in 'utf-8' format then put that info in
the PO-file.
Example:
```...removed some lines here...
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
'''
== How to use gettext ==
In your Erlang/Yaws file, whenever you have a string that
should be possible to be presented in a different language,
you wrap it with one of the gettext macros ?TXT/1 or ?TXT2.
Example:
```-include_lib("gettext/include/gettext.hrl").
hello(LangCode) ->
?TXT2("Hello World", LangCode).
'''
The ?TXT macro will be substituted with a call to:
```gettext:key2str("Hello World", LangCode)'''
which will try to lookup the string "Hello World" in the
LangCode DB. If no such DB can be found the string will just
be returned as is. This way no string will ever disappear
since it (at least) always will fallback to the original
string.
To make it extra convenient, you can use the ?TXT macro
which just takes one argument and expands to:
```gettext:key2str("Hello World", get(gettext_language))'''
As you can see it assume that you already have put the
language code into the process dictionary using the
key: 'gettext_language'. This is useful for example
in a Yaws application where you perhaps get the prefered
language code from the headers of the HTTP request.
Just put the language code into the process dictonary
and you are done!
== The gettext database ==
There are two ways you can control where the 'gettext' database
is located. The first way is to set the environment variable:
'GETTEXT_DIR' to point to the directory where you want 'gettext'
to store its data. The second way is to provide a callback
function named: gettext_dir/0. You specify the module, either
by setting the environment variable 'GETTEXT_CBMOD', or by
giving it as an argument in your supervisor code that setup
the gettext_server (see example in gettext_sup.erl).
Example:
```M:gettext_dir/0 ==> "/tmp/gettext_server_db"'''
In case no directory can be obtained, the priv dir of
'gettext' will be used, which may cause trouble if
the directory is write protected.
The directory structure will look like this:
```$(GETTEXT_DIR)/lang/gettext_server_db.dets
$(GETTEXT_DIR)/lang/default/$(GETTEXT_DEF_LANG)/gettext.po
$(GETTEXT_DIR)/lang/custom/$(LANG)/gettext.po'''
The dets file contains the actual lookup database.
The 'default' directory will only contain one subdirectory
with the name of your default language (e.g "en").
The 'custom' directory will contain one subdirectory
for each further language you have, each subdirectory containing
a translated gettext.po file.
If you want add a translated PO-file you call the function:
```gettext:store_pofile(LanguageCode, BinPOfile)'''
See the example section below.
== How to create the initial PO-file ==
This step requires you to setup some Makefile support.
The top 'gettext' Makefile contains a target 'example'
which will run make using the 'Makefile.gettext' makefile.
Take a look at the Makefile.gettext. At the top you
specify the directories that should be processed, i.e
where there are code containing ?TXT macros. As you
can see from the example; we have specified that it is
the 'esmb' application that should be processed.
We also specify where the 'gettext' data dir is located.
Then, for each directory to be processed, we run make
with a special target named 'gettext'. If you look into
the esmb application you can see that its top Makefile
has got such a target. All this target needs to do is
to remove any dependency files (e.g beam files) and then
run make to compile them again.
All source files that are using the ?TXT macro are also
including the 'gettext/include/gettext.hrl' file which
contains a parse-transform. This parse-transform will
store all strings that was wrapped with the ?TXT
macro into a temporary database.
Going back to the 'Makefile.gettext' file again you can
see that when all processing is finished, we call a last
'generation' step. Where we will extract all data from
the temporary DB and generate the 'initial' PO-file.
== Example session ==
To create our database directory and generate the initial
PO-file we run:
```# cd gettext'''
```# make example'''
(compile printouts removed here)
```# cat /tmp/gettext_example/lang/default/en/gettext.po'''
(look at the nice PO-file we have got)
Before we start our Erlang system we setup an environment
variable pointing to our 'gettext' database directory:
```export GETTEXT_DIR=/tmp/gettext_example'''
```# erl -pa ./ebin -pa ../esmb/ebin'''
This will create and populate the dets file
```1> gettext_server:start().
{ok,<0.35.0>}'''
We are calling our example application
```2> esmb_gettext:start().
"Hello World"'''
Changing to a unknown (at the moment) language code
```3> put(gettext_language, "swe").
undefined'''
Falling back to the original string
```4> esmb_gettext:start().
"Hello World"'''
Now read in a Swedish translation
```5> {_, Bin} = file:read_file("swedish.po").
{ok,<<35,32,...>>}'''
Store the translation
```6> gettext:store_pofile("swe", Bin).
ok'''
Now look at that...nice !!
<pre>
7&gt; esmb_gettext:start().
"Hej, V&#228;rlden!"
</pre>
Change to another language
```8> put(gettext_language, "en").
"swe"'''
Perfect !!
```9> esmb_gettext:start().
"Hello World"'''
Get the character set used for a language.
```10> gettext:lang2cset("swe").
{ok,"iso-8859-1"}'''
== Final remarks ==
You can easily write some code on top of this to make it
possible to export the initial PO-file and to import translated
PO-files. Also, take a look at the iso639.erl file which can
be helpful if you want to present some standardized language
codes and their full language names.
If you run a Web application, it is important that you tell
the Web browser what character set you are using. To support
this, you can use the function:
```gettext:lang2cset(LanguageCode)'''
This way you can make sure that the browser can display your
pages correctly. It is even possible to convert from the
character set you have to what the Web browser wants if
you make use of the 'iconv' library that comes with the
'esmb' application.
Cheers, Tobbe
Jump to Line
Something went wrong with that request. Please try again.