wCMF 4.1
Guides
Getting started
Architecture
Model
Persistence
Presentation
Configuration
Security
I18n & l10n
Tests
Versions
4.1.x
4.0.x
API
Classes
Hierarchy
Code
Support
home
travis
build
iherwig
wcmf
docs
api-src
framework_description
en
i18n_l10n.doxy
1
/*!
2
\page i18n_l10n I18n & l10n
3
<div class="has-toc"></div>
4
5
# Internationalization & localization # {#i18n_main}
6
7
_Internationalization_ of an application requires to identify all language dependent
8
resources and make them exchangeable for the actual _localization_ into a specific
9
language. This includes __static__ and __dynamic texts__ as well as __images__.
10
Since images are referenced by their filename or represented as text (e.g. _base64_
11
encoded), it is sufficient to focus on text.
12
13
## Static text ## {#i18n_static}
14
15
Static text refers to text used in __application templates__ or __messages__ generated
16
while the application is executed. To keep the application code language agnostic
17
only so called _text identifiers_ are used in these places and the actual
18
translation is retrieved by calling the
19
\link wcmf::lib::i18n::Message::getText `Message::getText`\endlink method:
20
21
<div class="php">
22
```
23
$textId = 'An error occured';
24
25
// retrieve the translation
26
$message = ObjectFactory::getInstance('Message');
27
$errorText = $message->getText($textId);
28
29
// use the translation
30
$ex = new Exception($errorText);
31
```
32
</div>
33
34
@note Implementations of \link wcmf::lib::i18n::Message `Message`\endlink
35
must return the _text identifier_, if no translation is found or the translation
36
is empty. This helps to simplify the translation process, if the default language
37
is used in _text identifiers_. In this case, no translation is required for the
38
default language.
39
40
If no language parameter is passed to the
41
\link wcmf::lib::i18n::Message::getText `Message::getText`\endlink method, the
42
returned translation will be in the application's __default user interface language__.
43
This language is determined in the following way:
44
45
1. Use the value of the `language` parameter of the `Message` configuration section
46
2. If not defined use the value of the global variable <code>$_SERVER['HTTP_ACCEPT_LANGUAGE']</code>
47
48
If parts of the text vary depending on the application state, it is necessary to
49
put __variables__ into the text identifier. Variable names are `%0%`, `%1%`, ...
50
and they are replaced in the order of the values passed into the
51
\link wcmf::lib::i18n::Message::getText `Message::getText`\endlink method:
52
53
<div class="php">
54
```
55
$textId = 'Logged in as %0% since %1%';
56
$parameters = [$username, $date];
57
58
// retrieve the translation
59
$message = ObjectFactory::getInstance('Message');
60
$loginMessage = $message->getText($textId, $parameters);
61
62
// use the translation
63
$view->setValue('loginMessage', $loginMessage);
64
```
65
</div>
66
67
### Template text ### {#i18n_static_tpl}
68
69
wCMF provides the `translate` plugin for embedding language dependent text into
70
_Smarty_ templates. The plugin is automatically included and used in the following
71
way:
72
73
<div class="php">
74
```
75
{translate text="An error occured"}
76
77
{* with variables *}
78
{translate text="Logged in as %0% since %1%" r0=$login r1=$logindate}
79
```
80
</div>
81
82
### Localization ### {#i18n_static_locale}
83
84
Since \link wcmf::lib::i18n::Message `Message`\endlink defines the interface, it
85
needs concrete implementations to actually get the translations. The
86
\link wcmf::lib::i18n::impl::FileMessage `FileMessage`\endlink class retrieves
87
translations from the file system. It expects one file per language defining
88
a language dependent array that maps text identifiers to translations.
89
The language code (e.g. _en_) is used to identify the language of the translation.
90
The file must be named like <em>messages_</em>code.<em>php</em>,
91
the variable like <em>$messages_</em>code.
92
93
The following __examples__ show definitions for English (_en_) and German (_de_)
94
texts, where the array keys are the text identifiers used in the application and
95
the values are the translations in the appropriate language.
96
97
<em>messages_en.php</em>
98
99
<div class="php">
100
```
101
$messages_en = [];
102
$messages_en['%0% selected'] = '';
103
$messages_en['Author'] = '';
104
$messages_en['Book'] = '';
105
```
106
</div>
107
108
<em>messages_de.php</em>
109
110
<div class="php">
111
```
112
$messages_de = [];
113
$messages_de['%0% selected'] = '%0% ausgewählt';
114
$messages_de['Author'] = 'Autor';
115
$messages_de['Book'] = 'Buch';
116
```
117
</div>
118
119
@note Note that the text identifiers are in the application's default language
120
(_en_) and therefor no translations need to be provided.
121
122
The default __configuration__ of \link wcmf::lib::i18n::Message `Message`\endlink
123
is as follows:
124
125
<div class="ini">
126
```
127
[Message]
128
__class = wcmf\lib\i18n\impl\FileMessage
129
localeDir = app/locale/
130
language = en
131
```
132
</div>
133
134
The parameter `localeDir` defines the directory where
135
\link wcmf::lib::i18n::impl::FileMessage `FileMessage`\endlink searchs for
136
translation files and the `language` parameter defines the application's default
137
language.
138
139
### Tools ### {#i18n_static_tools}
140
141
The \ref app "default application" ships with a tool for finding translatable text
142
and generating localization files from it. After installing the application
143
it is available under `http://localhost/wcmf-default-app/tools/locale/`.
144
145
The tool uses \link wcmf::lib::util::I18nUtil `I18nUtil`\endlink internally to
146
search for occurrences of
147
148
- <code>->getText('Text to translate', ...)</code> as used in
149
<code>$message->getText('Text to translate', ...)</code> in PHP code
150
- `{translate:"Text to translate" ...}` as used in Smarty templates
151
- `Dict.translate("Text to translate", ...)` as used in the Javascript code of the
152
\ref app "default application"
153
154
_Text to translate_ is supposed to be the message to be localized. The tool generates
155
one localization file for each language puts it into the appropriate directory.
156
It's capable of merging already existing translations into the newly generated
157
files.
158
159
The tool's configuration is defined in the file _config.ini_ in the tool's directory
160
and defaults to:
161
162
<div class="ini">
163
```
164
[Application]
165
localeDir = app/locale/
166
167
[I18n]
168
searchDirs = {vendor/wcmf/wcmf/src/wcmf, app/}
169
exclude = {vendor, .git, .svn, test}
170
languages = {de, en}
171
```
172
</div>
173
174
## Model content ## {#i18n_dynamic}
175
176
Model content is initially created in the application's __default model language__,
177
which might differ from the _default user interface language_ (see \ref i18n_static).
178
Localization of the model content is done by using implementations of
179
\link wcmf::lib::i18n::Localization `Localization`\endlink. The interface defines
180
methods for loading and saving localized model content. The following code
181
demonstrates how to use it to get translated content:
182
183
<div class="php">
184
```
185
$oid = new ObjectId('Book', 1);
186
187
// retrieve a localized entity instance
188
$localization = ObjectFactory::getInstance('localization');
189
$bookDe = $localization->loadTranslatedObject($oid, 'de');
190
```
191
</div>
192
193
### Localization ### {#i18n_dynamic_locale}
194
195
There are several strategies for storing localized versions of the content, all
196
having advantages and disadvantages regarding extensibility and performance. The
197
idea behind the
198
\link wcmf::lib::i18n::impl::DefaultLocalization `DefaultLocalization`\endlink
199
implementation is to keep the domain model clear of localization related attributes
200
by storing translations in a separate entity type. Using one entity type for all
201
content leads to more flexibility when extending the domain model.
202
203
The __translation entity type__ must have the following attributes:
204
205
- `objectid` object id of the translated entity (e.g. _Book:1_)
206
- `attribute` translated attribute (e.g. _title_)
207
- `language` the language code of the translation (e.g. _en_)
208
- `translation` the actual translation
209
210
The supported content languages are either defined in the `Languages` configuration
211
section (see below) or in the language entity type that is used by
212
\link wcmf::lib::i18n::impl::DefaultLocalization `DefaultLocalization`\endlink,
213
if the configuration section does not exist.
214
215
The __language entity type__ must have the following attributes:
216
217
- `code` language code (e.g. _en_)
218
- `name` language name (e.g. _English_)
219
220
The following __example__ demonstrates the creation of localized content
221
using the \link wcmf::lib::i18n::Localization `Localization`\endlink interface:
222
223
<div class="php">
224
```
225
$oid = new ObjectId('Book', 1);
226
227
// retrieve the original entity instance
228
$persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
229
$book = $persistenceFacade->load($oid);
230
231
// localize the instance
232
$book->setValue('title', 'Übersetzter Titel');
233
234
// save the translation
235
$localization = ObjectFactory::getInstance('localization');
236
$localization->saveTranslation($book, 'de');
237
```
238
</div>
239
240
The localization __configuration__ of the \ref app "default application" is the
241
following:
242
243
<div class="ini">
244
```
245
[Localization]
246
__class = wcmf\lib\i18n\impl\DefaultLocalization
247
defaultLanguage = en
248
languageType = app.src.model.wcmf.Language
249
translationType = app.src.model.wcmf.Translation
250
251
[Languages]
252
de = Deutsch
253
en = English
254
```
255
</div>
256
257
In this example the _default model language_ is set to English and the
258
_language entity type_ is ignored, because the available languages are defined
259
in the configuration.
260
*/