Translator.h
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/common/Translator.h
22 
23  \brief This class is designed for dealing with multi-language text translation in TerraLib.
24 */
25 
26 #ifndef __TERRALIB_COMMON_INTERNAL_TRANSLATOR_H
27 #define __TERRALIB_COMMON_INTERNAL_TRANSLATOR_H
28 
29 // TerraLib
30 #include "../BuildConfig.h"
31 #include "Config.h"
32 
33 #ifdef TERRALIB_TRANSLATOR_ENABLED
34 #include "Singleton.h"
35 
36 // STL
37 #include <map>
38 #include <string>
39 
40 namespace te
41 {
42  namespace common
43  {
44  /*!
45  \class Translator
46 
47  \brief This singleton is designed to deal with multi-language text translation in TerraLib.
48 
49  The Translator job is to manage "Internationalization" of the TerraLib messages.
50  This class is all about Native Language Support.
51  For each string you want to have a translation, you have to use
52  the special macro TR_XXX("string"). This macro does nothing with your code;
53  its job is just to mark the code fragment that you want to translate and it does
54  all the job of calling the translation for you. Actually, the translation
55  is done using GNU Text Utilities. So, you can use commands like:
56  \verbatim
57  terralib# xgettext -D ../src/terralib/common -d tlcommon -o tlcommon.pot -f common.txt --keyword=TE_TR --from-code=UTF-8 --msgid-bugs-address=gribeiro.mg@gmail.com -p common
58  terralib# msgmerge --directory=common -U tlcommon-pt_BR.po tlcommon.pot
59  msgfmt --directory=common -c -v -o common/tlcommon-pt_BR.mo tlcommon-pt_BR.po
60  \endverbatim
61 
62  Each module must define its translation macro. For example, in the
63  Common module we define the macro TE_TR, and all strings in the Common module are marked like:
64 
65  \code
66  #include <terralib/common/Translator.h>
67  ...
68  char* msg = TE_TR("My Message");
69  ...
70  or
71  ...
72  std::cout << TE_TR("Other message");
73  ...
74  \endcode
75 
76  Note that all marked messages will be part of a .pot file from where you can
77  create several po documents, one for each idiom. These .po files
78  can be used to generate a .mo binary file with the translation.
79 
80  To create a translation macro, just do the following "define":
81  \code
82  #define TR_MYMODULE(message) TR(message, MY_MODULE_TEXT_DOMAIN)
83  \endcode
84 
85  It is recommended that you create a text domain for your module like:
86  \code
87  #define MY_MODULE_TEXT_DOMAIN "mymodule"
88  #define MY_MODULE_TEXT_DOMAIN_DIR "locale"
89  \endcode
90 
91  Then you can create a initialization routine for registering your module's text domain (i.e. the message catalog of your module):
92  \code
93  #include <terralib/common/Translator.h>
94  ...
95  te::common::Translator::getInstance().addTextDomain(MY_MODULE_TEXT_DOMAIN, MY_MODULE_TEXT_DOMAIN_DIR);
96  \endcode
97 
98  This will register your module text domain, enabling the selection of the domain
99  the strings are coming from when you use the macro TR_MYMODULE.
100 
101  You can create plurals like:
102  \code
103  int n = f(...);
104  const char* c = TR_PLURAL_COMMON("The module was initialized!", "The modules were initialized!", n);
105  \endcode
106 
107  \warning It is supposed that PO files are UTF-8 encoded.
108 
109  \todo Investigar o uso da biblioteca de formatacao de mensagens da BOOST para que seja possivel construir mensagens parametrizadas como no caso do printf. Isso pode dar um efeito muito melhor aas mensagens!
110 
111  \todo O todo acima deve ser considerado e todo codigo deve ser visto para poder colocar caracteres curinga dentro da mensagem que sejam substituidas, como o printf e cia!
112 
113  \todo Investigar o uso de mensagens no plural: http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html#Plural-forms.
114 
115  \ingroup common
116  */
117  class TECOMMONEXPORT Translator : public Singleton<Translator>
118  {
119  friend class Singleton<Translator>;
120 
121  public:
122 
123  /** @name Translation Methods
124  * Methods that can be used to tranlate texts.
125  */
126  //@{
127 
128  /*!
129  \brief It tries to translate the specified text string.
130 
131  If no translation is available it will return the
132  original message (always in English).
133 
134  \param message The text to be translated.
135  \param textDomain The text domain used in translation. A text domain is the name of the catalog used to translate the message.
136 
137  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
138 
139  \note The returned message is UTF-8 encoded.
140  */
141  const char* translate(const std::string& message,
142  const std::string& textDomain);
143 
144  /*!
145  \brief It tries to translate the specified text string.
146 
147  If no translation is available it will return the
148  original message (always in English).
149 
150  \param message The text to be translated.
151  \param textDomain The text domain used in the translation. A text domain is the name of the catalog used to translate the message.
152 
153  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
154 
155  \note The returned message is UTF-8 encoded.
156  */
157  const char* translate(const char* message,
158  const char* textDomain);
159 
160  /*!
161  \brief It tries to translate the specified text string accounting for plural forms.
162 
163  If no translation is available it will return the
164  original message (always in English).
165 
166  \param textDomain The text domain used in the translation. A text domain is the name of the catalog used to translate the message.
167  \param msg1 The singular form of the text to be translated.
168  \param msg2 The plural form of the text to be translated.
169  \param n This parameter is used to determine the plural form.
170 
171  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
172 
173  \note The returned message is UTF-8 encoded.
174  */
175  const char* translate(const std::string& textDomain,
176  const std::string& msg1,
177  const std::string& msg2,
178  unsigned int n);
179 
180  /*!
181  \brief It tries to translate the specified text string accounting for plural forms.
182 
183  If no translation is available it will return the
184  original message (always in English).
185 
186  \param textDomain The text domain used in translation. A text domain is the name of the catalog used to translate the message.
187  \param msg1 The singular form of the text to be translated.
188  \param msg2 The plural form of the text to be translated.
189  \param n This parameter is used to determine the plural form.
190 
191  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
192 
193  \note The returned message is UTF-8 encoded.
194  */
195  const char* translate(const char* textDomain,
196  const char* msg1,
197  const char* msg2,
198  unsigned int n);
199 
200  /*!
201  \brief It adds a new text domain (text catalog) associated to a given directory.
202 
203  \param textDomain A given message domain (just a name). A text domain is the name of the catalog used to translate the message.
204  \param textDomainDir The base directory for the message catalogs (added with full path).
205 
206  \return A NULL string if the domain is not added.
207 
208  \exception Exception If the text domain already exists it raises an exception. If you are not sure about the existence of a text domain, use the exist() method.
209  */
210  const char* addTextDomain(const std::string& textDomain, const std::string& textDomainDir);
211 
212  /*!
213  \brief It can be used to specify the output character set for a given message catalog.
214 
215  \param textDomain A given message domain (just a name). A text domain is the name of the catalog used to translate the message.
216  \param codeset If NULL returns the currently selected codeset for the domain. A valid codeset name is, for instance, UTF-8.
217 
218  \return A pointer to a string containing the name of the selected codeset. Don't delete the returned pointer!
219 
220  \exception Exception If the text domain doesn't exists. If you are not sure about the existence of a text domain, use the exist() method.
221  */
222  const char* setTextDomainCodeSet(const std::string& textDomain, const std::string& codeset);
223 
224  /*!
225  \brief It returns true if the text domain (text catalog) exists and false otherwise.
226 
227  \param textDomain A given message domain (just a name).
228  */
229  bool exist(const std::string& textDomain);
230 
231  /*!
232  \brief It returns the base directory for the message catalog identified by the text domain.
233 
234  \param textDomain A given message domain (just a name).
235 
236  \return The base directory for the message catalog identified by the text domain.
237 
238  \note If the domain doesn't exist, it will return an empty string.
239  */
240  std::string getTextDomainDir(const std::string& textDomain);
241 
242  //@}
243 
244  protected:
245 
246  /*! \brief Singleton constructor must be protected. */
247  Translator();
248 
249 
250  /* \brief Destructor. */
251  ~Translator();
252 
253  private:
254 
255  std::map<std::string, std::string> m_textDomainMap; //!< A map from text domains to base directory for the message catalog.
256  };
257 
258  } // end namespace common
259 } // end namespace te
260 
261 #endif // TERRALIB_TRANSLATOR_ENABLED
262 
263 /** @name Internationalization Defines
264  * Flags for TerraLib code internationalization.
265  */
266 //@{
267 
268 
269 // Check if the TR macro has already been defined
270 // by another application... if so, it will output
271 // an error message and stop compiling!
272 #ifdef TERRALIB_TRANSLATOR_ENABLED
273 #ifdef TE_TR
274 #error "The TE_TR macro has been already defined by another application or code. Please, inform TerraLib Development Team <terralib-team@dpi.inpe.br>, we will be glad to help solving this problem!"
275 #endif
276 #endif
277 
278 /*!
279  \def TERRALIB_TEXT_DOMAIN
280 
281  \brief It contains the name of the text domain used in the translation of messages in TerraLib.
282  */
283 #define TERRALIB_TEXT_DOMAIN "terralib"
284 
285 /*!
286  \def TERRALIB_TEXT_DOMAIN_DIR
287 
288  \brief It contains the translation catalog directory.
289  */
290 #define TERRALIB_TEXT_DOMAIN_DIR "locale"
291 
292 
293 /*!
294  \def TE_ADD_TEXT_DOMAIN
295 
296  \brief It adds the given text domain located at domain-dir with the given codeset to the multilingual system.
297 
298  \note This macro will check if the domain already exists before doing anyting.
299  */
300 #ifdef TERRALIB_TRANSLATOR_ENABLED
301  #define TE_ADD_TEXT_DOMAIN(domain, domaindir, codeset) \
302  if(!te::common::Translator::getInstance().exist(domain)) \
303  { \
304  te::common::Translator::getInstance().addTextDomain(domain, domaindir); \
305  te::common::Translator::getInstance().setTextDomainCodeSet(domain, codeset); \
306  } \
307  ((void)0)
308 #else
309  #define TE_ADD_TEXT_DOMAIN(domain, domaindir, codeset) ((void)0)
310 #endif
311 
312 /*!
313  \def TE_GENERAL_TR
314 
315  \brief Try to translate the message according to the given domain. See the TE_TR macro for more infomation on how to create a translation mark for your code.
316  */
317 #ifdef TERRALIB_TRANSLATOR_ENABLED
318  #define TE_GENERAL_TR(message, domain) te::common::Translator::getInstance().getInstance().translate(message, domain)
319 #else
320  #define TE_GENERAL_TR(message, domain) message
321 #endif
322 
323 /*!
324  \def TE_GENERAL_TR_PLURAL
325 
326  \brief Try to translate the message according to the given domain and plural form. See the TE_TR_PLURAL macro for more infomation on how to create a translation mark for your code.
327  */
328 #ifdef TERRALIB_TRANSLATOR_ENABLED
329  #define TE_GENERAL_TR_PLURAL(domain, message1, message2, n) te::common::Translator::getInstance().getInstance().translate(domain, message1, message2, n)
330 #else
331  #define TE_GENERAL_TR_PLURAL(domain, message1, message2, n) (n > 1 ? message2 : message1)
332 #endif
333 
334 /*!
335  \def TE_TR
336 
337  \brief It marks a string in order to get translated.
338 
339  Example of usage:
340  \code
341  std::cout << TE_TR("My message!");
342 
343  throw Exception(TE_TR("My other message!"));
344  \endcode
345  */
346 #define TE_TR(message) TE_GENERAL_TR(message, TERRALIB_TEXT_DOMAIN)
347 
348 /*!
349  \def TE_TR_PLURAL
350 
351  \brief It marks a string in order to get translated according to plural form.
352 
353  Example of usage:
354  \code
355  int n = f(...);
356 
357  std::cout << TE_TR_PLURAL("One Message!", "Two Messages", n);
358 
359  throw Exception(TE_TR_PLURAL("One Message!", "Two Messages", n));
360  \endcode
361 
362  In the above example, the parameter n can be
363  a threshold that helps to choose between the first or the second construction.
364  If your trabslation file is configured with a theashold of 1,
365  indicating that if n > 1 must choose the second construction,
366  the plural versin will be choosed, otherwise, it will choose the
367  singular form (the fisrt one).
368  */
369 #define TE_TR_PLURAL(message1, message2, n) TE_GENERAL_TR_PLURAL(TERRALIB_TEXT_DOMAIN, message1, message2, n)
370 
371 //@}
372 
373 #endif // __TERRALIB_COMMON_INTERNAL_TRANSLATOR_H
374 
Configuration flags for the TerraLib Common Runtime module.
Template support for singleton pattern.
URI C++ Library.
#define TECOMMONEXPORT
You can use this macro in order to export/import classes and functions from this module.
Definition: Config.h:65