TerraLib and TerraView Wiki Page

This is an old revision of the document!


TerraLib.Core: Translator

The class te::core::Translator provides support for language translation using Boost.Locale.

This class is a singleton that can be used to translate messages according to the system locale and translation dictionaries.

Translation dictionaries are sets of textual and binary files that are created through the GNU Gettext tools.

The translation is not automatic, it is necessary to perform this process manually in the files “po”.

API

C++

The API for messages translation in TerraLib is defined by Translator class, shown below:

namespace te
{
  namespace core
  {
    /*!
      \class Translator
 
      \brief This singleton is designed to deal with multi-language text translation in TerraLib.
     */
    class TECOREEXPORT Translator
    {
 
      public:
 
        static Translator& instance();
 
        /*!
          \brief It tries to translate the specified text string.
 
          If no translation is available it will return the
          original message (always in English).
 
          \param message    The text to be translated.
 
          \return A string of the translated message. You must not delete the memory pointed by the returned pointer.
 
          \note The returned message is UTF-8 encoded.
         */
        std::string translate(const std::string& message);
 
        /*!
          \brief It tries to translate the specified text string.
 
          If no translation is available it will return the
          original message (always in English).
 
          \param message    The text to be translated.
 
          \return A string of the translated message. You must not delete the memory pointed by the returned pointer.
 
          \note The returned message is UTF-8 encoded.
         */
        std::string translate(const char* message);
 
        /*!
          \brief It tries to translate the specified text string accounting for plural forms.
 
          If no translation is available it will return the
          original message (always in English).
 
          \param msg1       The singular form of the text to be translated.
          \param msg2       The plural form of the text to be translated.
          \param n          This parameter is used to determine the plural form.
 
          \return A string of the translated message. You must not delete the memory pointed by the returned pointer.
 
          \note The returned message is UTF-8 encoded.
         */
        std::string translate(const std::string& msg1,
                              const std::string& msg2,
                              unsigned int n);
 
        /*!
          \brief It tries to translate the specified text string accounting for plural forms.
 
          If no translation is available it will return the
          original message (always in English).
 
          \param msg1       The singular form of the text to be translated.
          \param msg2       The plural form of the text to be translated.
          \param n          This parameter is used to determine the plural form.
 
          \return A string of the translated message. You must not delete the memory pointed by the returned pointer.
 
          \note The returned message is UTF-8 encoded.
         */
        std::string translate(const char* msg1,
                              const char* msg2,
                              unsigned int n);
 
        /*!
          \brief It sets the locale for the Translator.
 
          \param locale A string of the new locale.
         */
        void setLocale(const std::string &locale);
 
        /*!
          \brief It adds a new text domain (text catalog).
 
          \param textDomain    A given message domain (just a name). A text domain is the name of the catalog used to translate the message.
 
          \param dir Where the text domain is located.
 
          \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.
         */
        void addTextDomain(const std::string& textDomain, const std::string& dir);
 
 
        /*!
          \brief It returns true if the text domain (text catalog) exists and false otherwise.
 
          \param textDomain A given message domain (just a name).
         */
        bool exist(const std::string& textDomain);
    };
 
  } // end namespace core
}   // end namespace te

In addition to the class above, there are macros that assist in API usage process.

The macro TO ADD TEXT DOMAIN will register the name of a translation file in the language system and where it is located:

TE_ADD_TEXT_DOMAIN("terralib_mod_core", te::core::FindInTerraLibPath("share/terralib/translations"));

The macro TE_TR can be used to delimit text that should be translated:

std::cout << TE_TR("This text should be translated") << "\n";

When messages depend on the number of inflexion (plural), you should use the macro TE_TR_PLURAL:

std::cout << TE_TR_PLURAL("1 Layer is selected","2 Layers are selected", 1); // Irá traduzir para a primeira mensagem.
std::cout << TE_TR_PLURAL("1 Layer is selected","2 Layers are selected", 2); // Irá traduzir para a segunda mensagem.

The macro TE_TR_LANGUAGE should only be used by the application to inform which language is in use:

TE_TR_LANGUAGE("pt_BR"); // Para que as traduções sejam feitas para Português(Brasil).
TE_TR_LANGUAGE("es_ES"); // Para que as traduções sejam feitas para Espanhol.

CMake

To facilitate the creation of binary files containing the translated messages as well as their inclusion in the binary distribution of packages in TerraLib family applications, the macro TERRALIB_REGISTER_TRANSLATION was created in CMake to be able to automate this process. This macro is in build/cmake/terralib_macros.cmake file in the code repository.

All TerraLib libraries that need the message translation system should use the above macro in your build project files (CMakeLists.txt). It has the following form:

TERRALIB_REGISTER_TRANSLATION("library-name" "language" "po-file-directory" "mo-file-output-directory")

Where:

  • library-name: library name or executable set to target in CMake script. Ex: terralib_mod_core
  • language: region of translations. Ex: pt_BR
  • po-file-directory: folder of the translation file. The file in this folder must meet the following formation rule: library_name_language. Ex: terralib_mod_core_pt_BR.po
  • mo-file-output-directory: output folder to the binary file generated from the file containing the translations. Preferably, use a folder in the build tree of CMake project. Ex: ${CMAKE_BINARY_DIR}/share/terralib/translations

As an example, we can take the line of CMakeLists.txt file of the TerraLib.Core project library:

TERRALIB_REGISTER_TRANSLATION("terralib_mod_core" "pt_BR"
                              "${TERRALIB_ABSOLUTE_ROOT_DIR}/share/terralib/translations"
                              "${CMAKE_BINARY_DIR}/share/terralib/translations")

Exemplos

Os arquivos “.po” podem ser criados na linha de comando com as ferramentas da GNU Gettext ou através de ferramentas gráficas como o ​POEditor ou o Poedit.

A seguir, iremos mostrar como criar esses arquivos na linha de comando com as ferramentas da GNU Gettext.

Para começar um novo arquivo de tradução, primeiramente, temos que criar um arquivo com a extensão “.pot”, que conterá um template das mensagens identificadas no código fonte. O comando a seguir mostra como extrair as mensagens dos arquivos informados:

$ xgettext --from-code="UTF-8" --no-wrap --c++ --keyword=TE_TR --keyword=TE_TR_PLURAL:1,2 -o terralib_unittest_core.pot repo/unittest/core/translator/TsTranslator.cpp repo/unittest/core/encoding/TsCharEncoding.cpp

O comando acima irá produzir o arquivo terralib_unittest_core.pot.

Caso você ainda não tenha um arquivo com a extensão “.po”, no caso da criação de novas bibliotecas, utilize o comando abaixo para criar este arquivo onde deverão ser incluídas as traduções para um determinado idioma:

$ msginit --no-translator -l pt_BR -i terralib_unittest_core.pot -o terralib_unittest_core_pt_BR.po

O comando acima irá produzir o arquivo terralib_unittest_core_pt_BR.po.

Caso você já possua um arquivo “.po” e deseje apenas realizar uma atualização do mesmo, você pode fazer isso através do seguinte comando:

$ xgettext --from-code="UTF-8" --no-wrap --c++ --keyword=TE_TR --keyword=TE_TR_PLURAL:1,2 -o terralib_unittest_core.pot repo/unittest/core/translator/TsTranslator.cpp repo/unittest/core/encoding/TsCharEncoding.cpp
 
$ msgmerge -U --backup=none -q --lang=pt_BR terralib_unittest_core.pot terralib_unittest_core_pt_BR.po 

Nota: No comando xgettext, onde você está atualizando o arquivo template, você pode informar novos arquivos se necessário.

A criação dos arquivo binários com a extensão “.mo”, contendo as traduções para uso nos sistemas, é feita de forma automática no build através da macro TERRALIB_REGISTER_TRANSLATION. Para isso, acrescente no seu CMakeLists.txt o registro de traduções como mostrado abaixo:

TERRALIB_REGISTER_TRANSLATION("terralib_unittest_core" "pt_BR"
                              "${TERRALIB_ABSOLUTE_ROOT_DIR}/share/terralib/translations"
                              "${CMAKE_BINARY_DIR}/share/terralib/translations")

Nota: utilizar o mesmo nome da biblioteca ou executável no registro de sua tradução.

No seu código fonte inclua uma chamada à macro TE_ADD_TEXT_DOMAIN para adicionar em tempo de execução o seu arquivo de tradução. Veja o exemplo abaixo:

// TerraLib
#include <terralib/core/translator/Translator.h>
#include <terralib/core/utils/Platform.h>
 
// STL
#include <cstdlib>
#include <iostream>
 
int main(int argc, char *argv[])
{
// Add your your text domain, will throw and error if was already added
  TE_ADD_TEXT_DOMAIN("terralib_example_core_translator", te::core::FindInTerraLibPath("share/terralib/translations"));
 
  ... // your code goes here!
 
  return EXIT_SUCCESS;
}

Uma vez que o arquivo de tradução encontra-se carregado, as macros TE_TR e TE_TR_PLURAL irão produzir a tradução correta:

// TerraLib
#include <terralib/core/translator/Translator.h>
#include <terralib/core/utils/Platform.h>
 
// STL
#include <cstdlib>
#include <iostream>
 
int main(int argc, char *argv[])
{
  TE_ADD_TEXT_DOMAIN("terralib_example_core_translator", te::core::FindInTerraLibPath("share/terralib/translations"));
 
// if no translation is available, the phrase will result in the same message.
  std::cout << TE_TR("This text will remain the same, because there is no translation for it.") << "\n";
 
// set locale messages to pt_BR
  TE_TR_LANGUAGE("pt_BR");
  std::cout << TE_TR("This text will be in portuguese if your system locale is pt_BR") << "\n";
 
// set locale messages to en_US
  TE_TR_LANGUAGE("en_US");
  std::cout << TE_TR("This text will be in portuguese if your system locale is pt_BR") << "\n";
 
  return EXIT_SUCCESS;
}

References