forked from noss/erlang-gettext
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
287 lines (207 loc) · 8.43 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
Introduction
============
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.
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(".../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' 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).
Example:
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:
$(GETTEXT_DIR)/lang/gettext_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 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().
{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,83,79,77,69,32,68,69,83,67,82,73,80,84,73,86,69,32,84,73,84,76,69,46,10,35,...>>}
%% Store the translation
6> gettext:store_pofile("swe", Bin).
ok
%% Now look at that...nice !!
7> esmb_gettext:start().
"Hej Värld"
%% 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
Changed 2006-11-12
All API functions are now located in the gettext module, this
breaks backwards compability, but makes maintanence easier.
Example:
gettext_server:lang2cset(LanguageCode)
is now:
gettext:lang2cset(LanguageCode)
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(LanguageCode)
gettext:lang2cset(Server, LanguageCode)
where server is a registered process name that has been
started with:
gettext_server:start_link(CallBackMod, Name)
or
gettext_server:start(CallBackMod, Name)
Cheers Mikael Karlsson