Internationalization with Harbour

José Luis Sánchez
Harbour Magazine
Published in
5 min readDec 22, 2018

This is a traslation from the article ‘Internacionalización con Harbour’ written by Quim Ferrer para Harbour Magazine.

Introduction

Those of us who have been developing applications, programs or utilities for some time now, tend -some of us- to leave until the end, almost after the documentation, the issue of translating our programs into other languages.

Excuses such as I already will (unspecified future), I still have no demand or it is very expensive in time and resources, are usually the motivations for postponing ‘sine die’ the subject of translation.

For quite some time now, there have been tools generally from the GNU world such as gettext https://www.gnu.org/software/gettext that have facilitated the transition to the world of translations, organizing the work to be done, so that it can be multidisciplinary and collaborative.

GNU Tools allow us to automate tasks for our developments, mainly :

  • Extract variable-hosted strings from our source code
  • Group these strings as definitions in a template
  • Generate from the template above a file for each language to be translated
  • Obtain a binary file resulting from the compilation of translation files

At the technical level, the GNU-gettext translation system is based on the construction and maintenance of the following types of files:

  • POT. Portable object template. File obtained when extracting texts from an application. It is the text format to send to translators.
  • PO. Portable object. Text file received from translators. It includes the original texts and their correspondence with the translations.
  • MO. Object Machine. Compiled file (binary) obtained from the *.po file for each language of the translation.

The use of this gettext translation system on a massive scale by multilingual websites has facilitated ‘de facto’ adoption as a translation standard for various programming languages, for example in PHP.

Background information

One of the main problems for Harbour’s propagation (or evangelisation) is the lack of ‘understandable’ documentation for its potential audience. Harbour’s excellent developers provide the compiler with incredible functionalities in relation to an audience that Harbour considers a mere ‘translation’ of the CA-Clipper of the 1990s. But these fabulous ‘extensions’ sometimes do not reach their potential users.

Searching for this type of information usually requires following closely the Harbour development group and diving into its source code.

One of the first approaches I discovered to address the issue of Harbour translations was the excellent research work of Jose Luis, editor of Harbour Magazine in an old post on his blog http://www.alanit.com/2003/07/i18n-en-xharbour

At that time xHarbour had the first tools for internationalization and in this blog, the problem is described from the point of view of the developer in Harbour who also wants to use resources contained in *.rc, *.dll, and so on.

José Luis talks about a tool called hbdict.exe, which is in charge of extracting the literals treated with the i18n function. Of this tool, I am not aware that it is ported to Harbour nor we can have it, if anyone has information, it will be a pleasure to include it in this documentation.

The following research work leads me to the Harbour make utility usage guide, called hbmk2.exe. Reading the countless flags at my disposal, I pay attention to two significant options:

  • hbl[=<output>] output .hbl filename. %{hb_lng} macro is accepted in filename
  • -lng=<languages> list of languages to be replaced in %{hb_lng} macros in .pot/.po filenames and output .hbl/.po filenames. Comma separated list: -lng=en,hu-HU,de

This is where I first realize the relationship between Harbour and pot/po formats. The conclusion is obvious, Harbour does not deal with the compiled format *.mo as it has its own format, the *.hbl (HarBour Language?). At the binary level they are very similar and I don’t know why the Harbour developers opted for their own format and didn’t produce the standard format *.mo.

To use other make systems, harbour/bin has the hbi18n.exe utility that is also able to generate *.hbl output from *.po.

How can Harbour take advantage of GNU-gettext ?

With this small guide, I intend to facilitate the work of other developers who want to implement multilanguage in their applications.

  • To begin with, we define a macro to implement global changes in a stand alone way. In this example, I also transform the string to UTF8.
#define _txt( x ) hb_UTF8ToStr( hb_i18n_gettext(x) )
  • Set up our Harbour code
@ 2,1 SAY _txt(“Editar”)
  • Or Fivewin code:
REDEFINE SAY VAR _txt(“Editar”) ID 200 OF oDlg
  • Compile our source code to obtain the *.pot file
harbour -m -n -j app.prg
  • Dowload poedit, the free traslation tool from https://poedit.net/download
  • Run poedit and create the new traslation, File > New from POT/PO file. The first time that we run poedit, it will ask us
  • Ejecutar poedit y crear nueva traducción, Archivo-> Nueva desde archivo POT/PO. The first time we run poedit, it will ask us for the base translation language.
  • Choose the app.pot template generated in the Harbour compilation process. Poedit asks us for the translation language
  • Start with the traslations:
  • Save the translation, for example for English language en.po
  • We see that it also generates the *.mo file that we are not going to use.
  • Once the translation(s) is finished, it is time to generate the binary of the language or languages that we will load in our application. For this we have the superpower of hbmk2.exe, Harbour make utility.
hbmk2 -hbl en.po
  • The utility creates the en.hbl file from en.po
  • Now all we need to do is implement it in our application :
cFile := hb_MemoRead( “en.hbl” )if hb_i18n_Check( cFile )hb_i18n_Set( hb_i18n_RestoreTable(cFile) )endif

With this procedure, all the literals in source code are translated and if we want to change language at runtime, just point to another language set, calling the instructions above.

Each time there is a change in our code, you only have to generate the template file *.pot again, open each language file *.po and from the menu option poedit, Catalog->Update from POT file. The previous changes remain intact and the new entries are pending to be translated, with ease to search for them.

I leave you a link to github https://github.com/QuimFerrer/i18n with sample code and use of a make hbmk2 script, to produce the compilation in multiple languages automatically.

To finish, I encourage you to investigate, improve and comment, experiences you have in the internationalization and translation of your creations.

--

--