All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "Config.h"
31 
32 #include "terralib_config.h"
33 
34 #ifdef TERRALIB_TRANSLATOR_ENABLED
35 #include "Singleton.h"
36 
37 // STL
38 #include <map>
39 #include <string>
40 
41 namespace te
42 {
43  namespace common
44  {
45  /*!
46  \class Translator
47 
48  \brief This singleton is designed to deal with multi-language text translation in TerraLib.
49 
50  The Translator job is to manage "Internationalization" of the TerraLib messages.
51  This class is all about Native Language Support.
52  For each string you want to have a translation, you have to use
53  the special macro TR_XXX("string"). This macro does nothing with your code;
54  its job is just to mark the code fragment that you want to translate and it does
55  all the job of calling the translation for you. Actually, the translation
56  is done using GNU Text Utilities. So, you can use commands like:
57  \verbatim
58  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
59  terralib# msgmerge --directory=common -U tlcommon-pt_BR.po tlcommon.pot
60  msgfmt --directory=common -c -v -o common/tlcommon-pt_BR.mo tlcommon-pt_BR.po
61  \endverbatim
62 
63  Each module must define its translation macro. For example, in the
64  Common module we define the macro TE_TR, and all strings in the Common module are marked like:
65 
66  \code
67  #include <terralib/common/Translator.h>
68  ...
69  char* msg = TE_TR("My Message");
70  ...
71  or
72  ...
73  std::cout << TE_TR("Other message");
74  ...
75  \endcode
76 
77  Note that all marked messages will be part of a .pot file from where you can
78  create several po documents, one for each idiom. These .po files
79  can be used to generate a .mo binary file with the translation.
80 
81  To create a translation macro, just do the following "define":
82  \code
83  #define TR_MYMODULE(message) TR(message, MY_MODULE_TEXT_DOMAIN)
84  \endcode
85 
86  It is recommended that you create a text domain for your module like:
87  \code
88  #define MY_MODULE_TEXT_DOMAIN "mymodule"
89  #define MY_MODULE_TEXT_DOMAIN_DIR "locale"
90  \endcode
91 
92  Then you can create a initialization routine for registering your module's text domain (i.e. the message catalog of your module):
93  \code
94  #include <terralib/common/Translator.h>
95  ...
96  te::common::Translator::getInstance().addTextDomain(MY_MODULE_TEXT_DOMAIN, MY_MODULE_TEXT_DOMAIN_DIR);
97  \endcode
98 
99  This will register your module text domain, enabling the selection of the domain
100  the strings are coming from when you use the macro TR_MYMODULE.
101 
102  You can create plurals like:
103  \code
104  int n = f(...);
105  const char* c = TR_PLURAL_COMMON("The module was initialized!", "The modules were initialized!", n);
106  \endcode
107 
108  \warning It is supposed that PO files are UTF-8 encoded.
109 
110  \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!
111 
112  \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!
113 
114  \todo Investigar o uso de mensagens no plural: http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html#Plural-forms.
115 
116  \ingroup common
117  */
118  class TECOMMONEXPORT Translator : public Singleton<Translator>
119  {
120  friend class Singleton<Translator>;
121 
122  public:
123 
124  /** @name Translation Methods
125  * Methods that can be used to tranlate texts.
126  */
127  //@{
128 
129  /*!
130  \brief It tries to translate the specified text string.
131 
132  If no translation is available it will return the
133  original message (always in English).
134 
135  \param message The text to be translated.
136  \param textDomain The text domain used in translation. A text domain is the name of the catalog used to translate the message.
137 
138  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
139 
140  \note The returned message is UTF-8 encoded.
141  */
142  const char* translate(const std::string& message,
143  const std::string& textDomain);
144 
145  /*!
146  \brief It tries to translate the specified text string.
147 
148  If no translation is available it will return the
149  original message (always in English).
150 
151  \param message The text to be translated.
152  \param textDomain The text domain used in the translation. A text domain is the name of the catalog used to translate the message.
153 
154  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
155 
156  \note The returned message is UTF-8 encoded.
157  */
158  const char* translate(const char* message,
159  const char* textDomain);
160 
161  /*!
162  \brief It tries to translate the specified text string accounting for plural forms.
163 
164  If no translation is available it will return the
165  original message (always in English).
166 
167  \param textDomain The text domain used in the translation. A text domain is the name of the catalog used to translate the message.
168  \param msg1 The singular form of the text to be translated.
169  \param msg2 The plural form of the text to be translated.
170  \param n This parameter is used to determine the plural form.
171 
172  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
173 
174  \note The returned message is UTF-8 encoded.
175  */
176  const char* translate(const std::string& textDomain,
177  const std::string& msg1,
178  const std::string& msg2,
179  unsigned int n);
180 
181  /*!
182  \brief It tries to translate the specified text string accounting for plural forms.
183 
184  If no translation is available it will return the
185  original message (always in English).
186 
187  \param textDomain The text domain used in translation. A text domain is the name of the catalog used to translate the message.
188  \param msg1 The singular form of the text to be translated.
189  \param msg2 The plural form of the text to be translated.
190  \param n This parameter is used to determine the plural form.
191 
192  \return A pointer to the translated message. You must not delete the memory pointed by the returned pointer.
193 
194  \note The returned message is UTF-8 encoded.
195  */
196  const char* translate(const char* textDomain,
197  const char* msg1,
198  const char* msg2,
199  unsigned int n);
200 
201  /*!
202  \brief It adds a new text domain (text catalog) associated to a given directory.
203 
204  \param textDomain A given message domain (just a name). A text domain is the name of the catalog used to translate the message.
205  \param textDomainDir The base directory for the message catalogs (added with full path).
206 
207  \return A NULL string if the domain is not added.
208 
209  \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.
210  */
211  const char* addTextDomain(const std::string& textDomain, const std::string& textDomainDir);
212 
213  /*!
214  \brief It can be used to specify the output character set for a given message catalog.
215 
216  \param textDomain A given message domain (just a name). A text domain is the name of the catalog used to translate the message.
217  \param codeset If NULL returns the currently selected codeset for the domain. A valid codeset name is, for instance, UTF-8.
218 
219  \return A pointer to a string containing the name of the selected codeset. Don't delete the returned pointer!
220 
221  \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.
222  */
223  const char* setTextDomainCodeSet(const std::string& textDomain, const std::string& codeset);
224 
225  /*!
226  \brief It returns true if the text domain (text catalog) exists and false otherwise.
227 
228  \param textDomain A given message domain (just a name).
229  */
230  bool exist(const std::string& textDomain);
231 
232  /*!
233  \brief It returns the base directory for the message catalog identified by the text domain.
234 
235  \param textDomain A given message domain (just a name).
236 
237  \return The base directory for the message catalog identified by the text domain.
238 
239  \note If the domain doesn't exist, it will return an empty string.
240  */
241  std::string getTextDomainDir(const std::string& textDomain);
242 
243  //@}
244 
245  protected:
246 
247  /*! \brief Singleton constructor must be protected. */
248  Translator();
249 
250 
251  /* \brief Destructor. */
252  ~Translator();
253 
254  private:
255 
256  std::map<std::string, std::string> m_textDomainMap; //!< A map from text domains to base directory for the message catalog.
257  };
258 
259  } // end namespace common
260 } // end namespace te
261 
262 #endif // TERRALIB_TRANSLATOR_ENABLED
263 
264 /** @name Internationalization Defines
265  * Flags for TerraLib code internationalization.
266  */
267 //@{
268 
269 
270 // Check if the TR macro has already been defined
271 // by another application... if so, it will output
272 // an error message and stop compiling!
273 #ifdef TERRALIB_TRANSLATOR_ENABLED
274 #ifdef TE_TR
275 #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!"
276 #endif
277 #endif
278 
279 /*!
280  \def TERRALIB_TEXT_DOMAIN
281 
282  \brief It contains the name of the text domain used in the translation of messages in TerraLib.
283  */
284 #define TERRALIB_TEXT_DOMAIN "terralib"
285 
286 /*!
287  \def TERRALIB_TEXT_DOMAIN_DIR
288 
289  \brief It contains the translation catalog directory.
290  */
291 #define TERRALIB_TEXT_DOMAIN_DIR "locale"
292 
293 
294 /*!
295  \def TE_ADD_TEXT_DOMAIN
296 
297  \brief It adds the given text domain located at domain-dir with the given codeset to the multilingual system.
298 
299  \note This macro will check if the domain already exists before doing anyting.
300  */
301 #ifdef TERRALIB_TRANSLATOR_ENABLED
302  #define TE_ADD_TEXT_DOMAIN(domain, domaindir, codeset) \
303  if(!te::common::Translator::getInstance().exist(domain)) \
304  { \
305  te::common::Translator::getInstance().addTextDomain(domain, domaindir); \
306  te::common::Translator::getInstance().setTextDomainCodeSet(domain, codeset); \
307  } \
308  ((void)0)
309 #else
310  #define TE_ADD_TEXT_DOMAIN(domain, domaindir, codeset) ((void)0)
311 #endif
312 
313 /*!
314  \def TE_GENERAL_TR
315 
316  \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.
317  */
318 #ifdef TERRALIB_TRANSLATOR_ENABLED
319  #define TE_GENERAL_TR(message, domain) te::common::Translator::getInstance().getInstance().translate(message, domain)
320 #else
321  #define TE_GENERAL_TR(message, domain) message
322 #endif
323 
324 /*!
325  \def TE_GENERAL_TR_PLURAL
326 
327  \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.
328  */
329 #ifdef TERRALIB_TRANSLATOR_ENABLED
330  #define TE_GENERAL_TR_PLURAL(domain, message1, message2, n) te::common::Translator::getInstance().getInstance().translate(domain, message1, message2, n)
331 #else
332  #define TE_GENERAL_TR_PLURAL(domain, message1, message2, n) (n > 1 ? message2 : message1)
333 #endif
334 
335 /*!
336  \def TE_TR
337 
338  \brief It marks a string in order to get translated.
339 
340  Example of usage:
341  \code
342  std::cout << TE_TR("My message!");
343 
344  throw Exception(TE_TR("My other message!"));
345  \endcode
346  */
347 #define TE_TR(message) TE_GENERAL_TR(message, TERRALIB_TEXT_DOMAIN)
348 
349 /*!
350  \def TE_TR_PLURAL
351 
352  \brief It marks a string in order to get translated according to plural form.
353 
354  Example of usage:
355  \code
356  int n = f(...);
357 
358  std::cout << TE_TR_PLURAL("One Message!", "Two Messages", n);
359 
360  throw Exception(TE_TR_PLURAL("One Message!", "Two Messages", n));
361  \endcode
362 
363  In the above example, the parameter n can be
364  a threshold that helps to choose between the first or the second construction.
365  If your trabslation file is configured with a theashold of 1,
366  indicating that if n > 1 must choose the second construction,
367  the plural versin will be choosed, otherwise, it will choose the
368  singular form (the fisrt one).
369  */
370 #define TE_TR_PLURAL(message1, message2, n) TE_GENERAL_TR_PLURAL(TERRALIB_TEXT_DOMAIN, message1, message2, n)
371 
372 //@}
373 
374 #endif // __TERRALIB_COMMON_INTERNAL_TRANSLATOR_H
375 
Configuration flags for the TerraLib Common Runtime module.
Template support for singleton pattern.
#define TECOMMONEXPORT
You can use this macro in order to export/import classes and functions from this module.
Definition: Config.h:68