Deprecated mirror of erlang gettext lib, use
Switch branches/tags
Nothing to show
Pull request Compare This branch is 1 commit ahead of noss:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



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.

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':

#: esmb_gettext.erl:13 
msgid ""
"Hello World"
msgstr ""
"Hej Värld"


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.

...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.


  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 

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' DB 

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


 M:gettext_dir/0 ==> "/tmp/gettext_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:


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 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 jungerl version of 'gettext' has a simple example
prepared for you to look at. The top 'gettext' Makefile
contains a target 'jungerl_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 jungerl/lib/gettext

# make jungerl_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 fill create and populate the dets file
1> gettext_server:start().

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

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

%% Store the translation
6> gettext:store_pofile("swe", Bin).

%% Now look at that...nice !!
7> esmb_gettext:start().                   
"Hej Värld"

%% Change to another language
8> put(gettext_language, "en").            

%% Perfect !!
9> esmb_gettext:start().       
"Hello World"

%% Get the character set used for a language.
10> gettext:lang2cset("swe").

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: 


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

Changed 2006-11-12
All API functions are now located in the gettext module, this
breaks backwards compability, but makes maintanence easier.


is now:


Added: 2006-11-12
Running several applications

In order to run several applications with diffent PO-files 
at the same time a new possibility to start a named process
(that creates an own ets-table) has been added. So there are
now two variants of every function in the API, example :
  gettext:lang2cset(Server, LanguageCode) 
where server is a  registered process name that has been 
started with:
  gettext_server:start_link(CallBackMod, Name)
 gettext_server:start(CallBackMod, Name)

Cheers Mikael Karlsson