jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: A tutorial on Native Language Support using GNU gettext jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68:

A tutorial on Native Language Support using GNU gettext

jpayne@68: jpayne@68:

G. Mohanty

jpayne@68:

Revision 0.3: 24 July 2004

jpayne@68:
jpayne@68: jpayne@68:

Abstract:

jpayne@68:
jpayne@68: The use of the GNU gettext utilities to implement support for native jpayne@68: languages is described here. Though, the language to be supported is jpayne@68: considered to be Oriya, the method is generally applicable. Likewise, while jpayne@68: Linux was used as the platform here, any system using GNU gettext should work jpayne@68: in a similar fashion. jpayne@68: jpayne@68:

jpayne@68: We go through a step-by-step description of how to make on-screen messages jpayne@68: from a toy program to appear in Oriya instead of English; starting from the jpayne@68: programming and ending with the user's viewpoint. Some discussion is also made jpayne@68: of how to go about the task of translation. jpayne@68:

jpayne@68:

jpayne@68:

jpayne@68: Introduction jpayne@68:

jpayne@68: Currently, both commercial and free computer software is typically written and jpayne@68: documented in English. Till recently, little effort was expended towards jpayne@68: allowing them to interact with the user in languages other than English, thus jpayne@68: leaving the non-English speaking world at a disadvantage. However, that jpayne@68: changed with the release of the GNU gettext utilities, and nowadays most GNU jpayne@68: programs are written within a framework that allows easy translation of the jpayne@68: program message to languages other than English. Provided that translations jpayne@68: are available, the language used by the program to interact with the user can jpayne@68: be set at the time of running it. gettext manages to achieve this seemingly jpayne@68: miraculous task in a manner that simplifies the work of both the programmer jpayne@68: and the translator, and, more importantly, allows them to work independently jpayne@68: of each other. jpayne@68: jpayne@68:

jpayne@68: This article describes how to support native languages under a system using jpayne@68: the GNU gettext utilities. While it should be applicable to other versions of jpayne@68: gettext, the one actually used for the examples here is version jpayne@68: 0.12.1. Another system, called catgets, described in the X/Open jpayne@68: Portability Guide, is also in use, but we shall not discuss that here. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: A simple example jpayne@68:

jpayne@68: Our first example of using gettext will be the good old Hello World program, jpayne@68: whose sole function is to print the phrase “Hello, world!” to the terminal. jpayne@68: The internationalized version of this program might be saved in hello.c as: jpayne@68:
jpayne@68: 1    #include <libintl.h>
jpayne@68: 2    #include <locale.h>
jpayne@68: 3    #include <stdio.h>
jpayne@68: 4    #include <stdlib.h>
jpayne@68: 5    int main(void)
jpayne@68: 6    {
jpayne@68: 7      setlocale( LC_ALL, "" );
jpayne@68: 8      bindtextdomain( "hello", "/usr/share/locale" );
jpayne@68: 9      textdomain( "hello" );
jpayne@68: 10      printf( gettext( "Hello, world!\n" ) );
jpayne@68: 11      exit(0);
jpayne@68: 12    }
jpayne@68: 
jpayne@68: Of course, a real program would check the return values of the functions and jpayne@68: try to deal with any errors, but we have omitted that part of the code for jpayne@68: clarity. Compile as usual with gcc -o hello hello.c. The program should jpayne@68: be linked to the GNU libintl library, but as this is part of the GNU C jpayne@68: library, this is done automatically for you under Linux, and other systems jpayne@68: using glibc. jpayne@68: jpayne@68:

jpayne@68: The programmer's viewpoint jpayne@68:

jpayne@68: As expected, when the hello executable is run under the default locale jpayne@68: (usually the C locale) it prints “Hello, world!” in the terminal. Besides jpayne@68: some initial setup work, the only additional burden faced by the programmer is jpayne@68: to replace any string to be printed with gettext(string), i.e., to jpayne@68: instead pass the string as an argument to the gettext function. For lazy jpayne@68: people like myself, the amount of extra typing can be reduced even further by jpayne@68: a CPP macro, e.g., put this at the beginning of the source code file, jpayne@68:
jpayne@68:   #define _(STRING)    gettext(STRING)
jpayne@68: 
jpayne@68: and then use _(string) instead of gettext(string). jpayne@68: jpayne@68:

jpayne@68: Let us dissect the program line-by-line. jpayne@68: jpayne@68:

    jpayne@68:
  1. locale.h defines C data structures used to hold locale jpayne@68: information, and is needed by the setlocale function. libintl.h jpayne@68: prototypes the GNU text utilities functions, and is needed here by jpayne@68: bindtextdomain, gettext, and textdomain. jpayne@68:
  2. jpayne@68:
  3. The call to setlocale () on line 7, with LC_ALL as the first argument jpayne@68: and an empty string as the second one, initializes the entire current locale jpayne@68: of the program as per environment variables set by the user. In other words, jpayne@68: the program locale is initialized to match that of the user. For details see jpayne@68: “man setlocale.” jpayne@68:
  4. jpayne@68:
  5. The bindtextdomain function on line 8 sets the base directory for the jpayne@68: message catalogs for a given message domain. A message domain is a set of jpayne@68: translatable messages, with every software package typically having its own jpayne@68: domain. Here, we have used “hello” as the name of the message domain for jpayne@68: our toy program. As the second argument, /usr/share/locale, is the default jpayne@68: system location for message catalogs, what we are saying here is that we are jpayne@68: going to place the message catalog in the default system directory. Thus, we jpayne@68: could have dispensed with the call to bindtextdomain here, and this jpayne@68: function is useful only if the message catalogs are installed in a jpayne@68: non-standard place, e.g., a packaged software distribution might have jpayne@68: the catalogs under a po/ directory under its own main directory. See “man jpayne@68: bindtextdomain” for details. jpayne@68:
  6. jpayne@68:
  7. The textdomain call on line 9 sets the message domain of the current jpayne@68: program to “hello,” i.e., the name that we are using for our example jpayne@68: program. “man textdomain” will give usage details for the function. jpayne@68:
  8. jpayne@68:
  9. Finally, on line 10, we have replaced what would normally have been, jpayne@68:
    jpayne@68:   printf( "Hello, world!\n" );
    jpayne@68: 
    jpayne@68: with, jpayne@68:
    jpayne@68:   printf( gettext( "Hello, world!\n" ) );
    jpayne@68: 
    jpayne@68: (If you are unfamiliar with C, the jpayne@68: \n at the end of the string jpayne@68: produces a newline at the end of the output.) This simple modification to all jpayne@68: translatable strings allows the translator to work independently from the jpayne@68: programmer. gettextize eases the task of the programmer in adapting a jpayne@68: package to use GNU gettext for the first time, or to upgrade to a newer jpayne@68: version of gettext. jpayne@68:
  10. jpayne@68:
jpayne@68: jpayne@68:

jpayne@68: Extracting translatable strings jpayne@68:

jpayne@68: Now, it is time to extract the strings to be translated from the program jpayne@68: source code. This is achieved with xgettext, which can be invoked as follows: jpayne@68:

jpayne@68:   xgettext -d hello -o hello.pot hello.c
jpayne@68: 
jpayne@68: This processes the source code in hello.c, saving the output in hello.pot (the jpayne@68: argument to the -o option). jpayne@68: The message domain for the program should be specified as the argument jpayne@68: to the -d option, and should match the domain specified in the call to jpayne@68: textdomain (on line 9 of the program source). Other details on how to use jpayne@68: gettext can be found from “man gettext.” jpayne@68: jpayne@68:

jpayne@68: A .pot (portable object template) file is used as the basis for translating jpayne@68: program messages into any language. To start translation, one can simply copy jpayne@68: hello.pot to oriya.po (this preserves the template file for later translation jpayne@68: into a different language). However, the preferred way to do this is by jpayne@68: use of the msginit program, which takes care of correctly setting up some jpayne@68: default values, jpayne@68:


jpayne@68:   msginit -l or_IN -o oriya.po -i hello.pot
jpayne@68: 
jpayne@68: Here, the -l option defines the locale (an Oriya locale should have been jpayne@68: installed on your system), and the -i and -o options define the input and jpayne@68: output files, respectively. If there is only a single .pot file in the jpayne@68: directory, it will be used as the input file, and the -i option can be jpayne@68: omitted. For me, the oriya.po file produced by msginit would look like: jpayne@68:
jpayne@68:   # Oriya translations for PACKAGE package.
jpayne@68:   # Copyright (C) 2004 THE PACKAGE'S COPYRIGHT HOLDER
jpayne@68:   # This file is distributed under the same license as the PACKAGE package.
jpayne@68:   # Gora Mohanty <gora_mohanty@yahoo.co.in>, 2004.
jpayne@68:   #
jpayne@68:   msgid ""
jpayne@68:   msgstr ""
jpayne@68:   "Project-Id-Version: PACKAGE VERSION\n"
jpayne@68:   "Report-Msgid-Bugs-To: \n"
jpayne@68:   "POT-Creation-Date: 2004-06-22 02:22+0530\n"
jpayne@68:   "PO-Revision-Date: 2004-06-22 02:38+0530\n"
jpayne@68:   "Last-Translator: Gora Mohanty <gora_mohanty@yahoo.co.in>\n"
jpayne@68:   "Language-Team: Oriya\n"
jpayne@68:   "MIME-Version: 1.0\n"
jpayne@68:   "Content-Type: text/plain; charset=UTF-8\n"
jpayne@68:   "Content-Transfer-Encoding: 8bit\n"
jpayne@68:  
jpayne@68:   #: hello.c:10
jpayne@68:   msgid "Hello, world!\n"
jpayne@68:   msgstr ""
jpayne@68: 
jpayne@68: msginit prompted for my email address, and probably obtained my real name jpayne@68: from the system password file. It also filled in values such as the revision jpayne@68: date, language, character set, presumably using information from the or_IN jpayne@68: locale. jpayne@68: jpayne@68:

jpayne@68: It is important to respect the format of the entries in the .po (portable jpayne@68: object) file. Each entry has the following structure: jpayne@68:

jpayne@68:   WHITE-SPACE
jpayne@68:   #  TRANSLATOR-COMMENTS
jpayne@68:   #. AUTOMATIC-COMMENTS
jpayne@68:   #: REFERENCE...
jpayne@68:   #, FLAG...
jpayne@68:   msgid UNTRANSLATED-STRING
jpayne@68:   msgstr TRANSLATED-STRING
jpayne@68: 
jpayne@68: where, the initial white-space (spaces, tabs, newlines,...), and all jpayne@68: comments might or might not exist for a particular entry. Comment lines start jpayne@68: with a '#' as the first character, and there are two kinds: (i) manually jpayne@68: added translator comments, that have some white-space immediately following the jpayne@68: '#,' and (ii) automatic comments added and maintained by the gettext tools, jpayne@68: with a non-white-space character after the '#.' The msgid line contains jpayne@68: the untranslated (English) string, if there is one for that PO file entry, and jpayne@68: the msgstr line is where the translated string is to be entered. More on jpayne@68: this later. For details on the format of PO files see gettext::Basics::PO jpayne@68: Files:: in the Emacs info-browser (see Appdx. A for an jpayne@68: introduction to using the info-browser in Emacs). jpayne@68: jpayne@68:

jpayne@68: Making translations jpayne@68:

jpayne@68: The oriya.po file can then be edited to add the translated Oriya jpayne@68: strings. While the editing can be carried out in any editor if one is careful jpayne@68: to follow the PO file format, there are several editors that ease the task of jpayne@68: editing PO files, among them being po-mode in Emacs, kbabel, gtranslator, jpayne@68: poedit, etc. Appdx. B describes features of some of jpayne@68: these editors. jpayne@68: jpayne@68:

jpayne@68: The first thing to do is fill in the comments at the beginning and the header jpayne@68: entry, parts of which have already been filled in by msginit. The lines in jpayne@68: the header entry are pretty much self-explanatory, and details can be found in jpayne@68: the gettext::Creating::Header Entry:: info node. After that, the remaining jpayne@68: work consists of typing the Oriya text that is to serve as translations for jpayne@68: the corresponding English string. For the msgstr line in each of the jpayne@68: remaining entries, add the translated Oriya text between the double quotes; jpayne@68: the translation corresponding to the English phrase in the msgid string jpayne@68: for the entry. For example, for the phrase “Hello world! jpayne@68: \n” in jpayne@68: oriya.po, we could enter “ନମସ୍କାର jpayne@68: \n”. The final jpayne@68: oriya.po file might look like: jpayne@68:

jpayne@68:   # Oriya translations for hello example package.
jpayne@68:   # Copyright (C) 2004 Gora Mohanty
jpayne@68:   # This file is distributed under the same license as the hello example package.
jpayne@68:   # Gora Mohanty <gora_mohanty@yahoo.co.in>, 2004.
jpayne@68:   #
jpayne@68:   msgid ""
jpayne@68:   msgstr ""
jpayne@68:   "Project-Id-Version: oriya\n"
jpayne@68:   "Report-Msgid-Bugs-To: \n"
jpayne@68:   "POT-Creation-Date: 2004-06-22 02:22+0530\n"
jpayne@68:   "PO-Revision-Date: 2004-06-22 10:54+0530\n"
jpayne@68:   "Last-Translator: Gora Mohanty <gora_mohanty@yahoo.co.in>\n"
jpayne@68:   "Language-Team: Oriya\n"
jpayne@68:   "MIME-Version: 1.0\n"
jpayne@68:   "Content-Type: text/plain; charset=UTF-8\n"
jpayne@68:   "Content-Transfer-Encoding: 8bit\n"
jpayne@68:   "X-Generator: KBabel 1.3\n"
jpayne@68: 
jpayne@68:   #: hello.c:10
jpayne@68:   msgid "Hello, world!\n"
jpayne@68:   msgstr "ନମସ୍କାର\n"
jpayne@68: 
jpayne@68: jpayne@68:

jpayne@68: For editing PO files, I have found the kbabel editor suits me the best. The jpayne@68: only problem is that while Oriya text can be entered directly into kbabel jpayne@68: using the xkb Oriya keyboard layouts [1] and the entries jpayne@68: are saved properly, the text is not displayed correctly in the kbabel window jpayne@68: if it includes conjuncts. Emacs po-mode is a little restrictive, but strictly jpayne@68: enforces conformance with the PO file format. The main problem with it is that jpayne@68: it does not seem currently possible to edit Oriya text in Emacs. yudit jpayne@68: is the best at editing Oriya text, but does not ensure that the PO file format jpayne@68: is followed. You can play around a bit with these editors to find one that jpayne@68: suits your personal preferences. One possibility might be to first edit the jpayne@68: header entry with kbabel or Emacs po-mode, and then use yudit to enter jpayne@68: the Oriya text on the msgstr lines. jpayne@68: jpayne@68:

jpayne@68: Message catalogs jpayne@68:

jpayne@68: After completing the translations in the oriya.po file, it must be compiled to jpayne@68: a binary format that can be quickly loaded by the gettext tools. To do that, jpayne@68: use: jpayne@68:

jpayne@68:   msgfmt -c -v -o hello.mo oriya.po
jpayne@68: 
jpayne@68: The -c option does detailed checking of the PO file format, -v makes the jpayne@68: program verbose, and the output filename is given by the argument to the -o jpayne@68: option. Note that the base of the output filename should match the message jpayne@68: domain given in the first arguments to bindtextdomain and textdomain on jpayne@68: lines 8 and 9 of the example program in Sec. 2. The .mo jpayne@68: (machine object) file should be stored in the location whose base directory is jpayne@68: given by the second argument to bindtextdomain. The final location of the jpayne@68: file will be in the sub-directory LL/LC_MESSAGES or LL_CC/LC_MESSAGES under jpayne@68: the base directory, where LL stands for a language, and CC for a country. For jpayne@68: example, as we have chosen the standard location, /usr/share/locale, for our jpayne@68: base directory, and for us the language and country strings are “or” and jpayne@68: “IN,” respectively, we will place hello.mo in /usr/share/locale/or_IN. Note jpayne@68: that you will need super-user privilege to copy hello.mo to this system jpayne@68: directory. Thus, jpayne@68:

jpayne@68:   mkdir -p /usr/share/locale/or_IN/LC_MESSAGES
jpayne@68:   cp hello.mo /usr/share/locale/or_IN/LC_MESSAGES
jpayne@68: 
jpayne@68: jpayne@68:

jpayne@68: The user's viewpoint jpayne@68:

jpayne@68: Once the message catalogs have been properly installed, any user on the system jpayne@68: can use the Oriya version of the Hello World program, provided an Oriya locale jpayne@68: is available. First, change your locale with, jpayne@68:

jpayne@68:   echo $LANG
jpayne@68:   export LANG=or_IN
jpayne@68: 
jpayne@68: The first statement shows you the current setting of your locale (this is jpayne@68: usually en_US, and you will need it to reset the default locale at the end), jpayne@68: while the second one sets it to an Oriya locale. jpayne@68: jpayne@68:

jpayne@68: A Unicode-capable terminal emulator is needed to view Oriya output jpayne@68: directly. The new versions of both gnome-terminal and konsole (the KDE jpayne@68: terminal emulator) are Unicode-aware. I will focus on gnome-terminal as it jpayne@68: seems to have better support for internationalization. gnome-terminal needs to jpayne@68: be told that the bytes arriving are UTF-8 encoded multibyte sequences. This jpayne@68: can be done by (a) choosing Terminal -> Character Coding -> jpayne@68: Unicode (UTF-8), or (b) typing “/bin/echo -n -e jpayne@68: ' jpayne@68: \033% jpayne@68: \G'” in the terminal, or (c) by running jpayne@68: /bin/unicode_start. Likewise, you can revert to the default locale by (a) jpayne@68: choosing Terminal -> Character Coding -> Current Locale jpayne@68: (ISO-8859-1), or (b) “/bin/echo -n -e ' jpayne@68: \033% jpayne@68: \@',” or jpayne@68: (c) by running /bin/unicode_stop. Now, running the example program (after jpayne@68: compiling with gcc as described in Sec. 2) with, jpayne@68:


jpayne@68:   ./hello
jpayne@68: 
jpayne@68: should give you output in Oriya. Please note that conjuncts will most likely jpayne@68: be displayed with a “halant” as the terminal probably does not render Indian jpayne@68: language fonts correctly. Also, as most terminal emulators assume fixed-width jpayne@68: fonts, the results are hardly likely to be aesthetically appealing. jpayne@68: jpayne@68:

jpayne@68: An alternative is to save the program output in a file, and view it with jpayne@68: yudit which will render the glyphs correctly. Thus, jpayne@68:


jpayne@68:   ./hello > junk
jpayne@68:   yudit junk
jpayne@68: 
jpayne@68: Do not forget to reset the locale before resuming usual work in the jpayne@68: terminal. Else, your English characters might look funny. jpayne@68: jpayne@68:

jpayne@68: While all this should give the average user some pleasure in being able to see jpayne@68: Oriya output from a program without a whole lot of work, it should be kept in jpayne@68: mind that we are still far from our desired goal. Hopefully, one day the jpayne@68: situation will be such that rather than deriving special pleasure from it, jpayne@68: users take it for granted that Oriya should be available and are upset jpayne@68: otherwise. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: Adding complications: program upgrade jpayne@68:

jpayne@68: The previous section presented a simple example of how Oriya language support jpayne@68: could be added to a C program. Like all programs, we might now wish to further jpayne@68: enhance it. For example, we could include a greeting to the user by adding jpayne@68: another printf statement after the first one. Our new hello.c source jpayne@68: code might look like this: jpayne@68:
jpayne@68: 1    #include <libintl.h>
jpayne@68: 2    #include <locale.h>
jpayne@68: 3    #include <stdio.h>
jpayne@68: 4    #include <stdlib.h>
jpayne@68: 5    int main(void)
jpayne@68: 6    {
jpayne@68: 7      setlocale( LC_ALL, "" );
jpayne@68: 8      bindtextdomain( "hello", "/usr/share/locale" );
jpayne@68: 9      textdomain( "hello" );
jpayne@68: 10      printf( gettext( "Hello, world!\n" ) );
jpayne@68: 11      printf( gettext( "How are you\n" ) );
jpayne@68: 12      exit(0);
jpayne@68: 13    }
jpayne@68: 
jpayne@68: For such a small change, it would be simple enough to just repeat the above jpayne@68: cycle of extracting the relevant English text, translating it to Oriya, and jpayne@68: preparing a new message catalog. We can even simplify the work by cutting and jpayne@68: pasting most of the old oriya.po file into the new one. However, real programs jpayne@68: will have thousands of such strings, and we would like to be able to translate jpayne@68: only the changed strings, and have the gettext utilities handle the drudgery jpayne@68: of combining the new translations with the old ones. This is indeed possible. jpayne@68: jpayne@68:

jpayne@68: Merging old and new translations jpayne@68:

jpayne@68: As before, extract the translatable strings from hello.c to a new portable jpayne@68: object template file, hello-new.pot, using xgettext, jpayne@68:

jpayne@68:   xgettext -d hello -o hello-new.pot hello.c
jpayne@68: 
jpayne@68: Now, we use a new program, msgmerge, to merge the existing .po file with jpayne@68: translations into the new template file, viz., jpayne@68:

jpayne@68:   msgmerge -U oriya.po hello-new.pot
jpayne@68: 
jpayne@68: The -U option updates the existing jpayne@68: .po file, oriya.po. We could have chosen to instead create a new .po file by jpayne@68: using “-o <filename>” instead of -U. The updated .po file will still jpayne@68: have the old translations embedded in it, and new entries with untranslated jpayne@68: msgid lines. For us, the new lines in oriya.po will look like, jpayne@68:
jpayne@68:   #: hello.c:11
jpayne@68:   msgid "How are you?\n"
jpayne@68:   msgstr ""
jpayne@68: 
jpayne@68: For the new translation, we could use, “ଆପଣ jpayne@68: କିପରି ଅଛନ୍ତି?” in jpayne@68: place of the English phrase “How are you?” The updated oriya.po file, jpayne@68: including the translation might look like: jpayne@68:
jpayne@68:   # Oriya translations for hello example package.
jpayne@68:   # Copyright (C) 2004 Gora Mohanty
jpayne@68:   # This file is distributed under the same license as the hello examplepackage.
jpayne@68:   # Gora Mohanty <gora_mohanty@yahoo.co.in>, 2004.
jpayne@68:   #
jpayne@68:   msgid ""
jpayne@68:   msgstr ""
jpayne@68:   "Project-Id-Version: oriya\n"
jpayne@68:   "Report-Msgid-Bugs-To: \n"
jpayne@68:   "POT-Creation-Date: 2004-06-23 14:30+0530\n"
jpayne@68:   "PO-Revision-Date: 2004-06-22 10:54+0530\n"
jpayne@68:   "Last-Translator: Gora Mohanty <gora_mohanty@yahoo.co.in>\n"
jpayne@68:   "Language-Team: Oriya\n"
jpayne@68:   "MIME-Version: 1.0\n"
jpayne@68:   "Content-Type: text/plain; charset=UTF-8\n"
jpayne@68:   "Content-Transfer-Encoding: 8bit\n"
jpayne@68:   "X-Generator: KBabel 1.3\n"
jpayne@68:   
jpayne@68:   #: hello.c:10
jpayne@68:   msgid "Hello, world!\n"
jpayne@68:   msgstr "ନମସ୍କାର\n"
jpayne@68: 
jpayne@68:   #: hello.c:11
jpayne@68:   msgid "How are you?\n"
jpayne@68:   msgstr "ଆପଣ କିପରି ଅଛନ୍ତି?\n"
jpayne@68: 
jpayne@68: jpayne@68:

jpayne@68: Compile oriya.po to a machine object file, and install in the appropriate jpayne@68: place as in Sec. 2.4. Thus, jpayne@68:


jpayne@68:   msgfmt -c -v -o hello.mo oriya.po
jpayne@68:   mkdir -p /usr/share/locale/or_IN/LC_MESSAGES
jpayne@68:   cp hello.mo /usr/share/locale/or_IN/LC_MESSAGES
jpayne@68: 
jpayne@68: You can test the Oriya output as above, after recompiling hello.c and running jpayne@68: it in an Oriya locale. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: More about gettext jpayne@68:

jpayne@68: The GNU gettext info pages provide a well-organized and complete description jpayne@68: of the gettext utilities and their usage for enabling Native Language jpayne@68: Support. One should, at the very least, read the introductory material at jpayne@68: gettext::Introduction::, and the suggested references in jpayne@68: gettext::Conclusion::References::. Besides the gettext utilities described in jpayne@68: this document, various other programs to manipulate .po files are discussed in jpayne@68: gettext:Manipulating::. Finally, support for programming languages other than jpayne@68: C/C++ is discussed in gettext::Programming Languages::. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: The work of translation jpayne@68:

jpayne@68: Besides the obvious program message strings that have been the sole focus of jpayne@68: our discussion here, there are many other things that require translation, jpayne@68: including GUI messages, command-line option strings, configuration files, jpayne@68: program documentation, etc. Besides these obvious aspects, there are a jpayne@68: significant number of programs and/or scripts that are automatically generated jpayne@68: by other programs. These generated programs might also themselves require jpayne@68: translation. So, in any effort to provide support for a given native language, jpayne@68: carrying out the translation and keeping up with program updates becomes a jpayne@68: major part of the undertaking, requiring a continuing commitment from the jpayne@68: language team. A plan has been outlined for the Oriya localization jpayne@68: project [2]. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: Acknowledgments jpayne@68:

jpayne@68: Extensive use has obviously been made of the GNU gettext manual in preparing jpayne@68: this document. I have also been helped by an article in the Linux jpayne@68: Journal [3]. jpayne@68: jpayne@68:

jpayne@68: This work is part of the project for enabling the use of Oriya under Linux. I jpayne@68: thank my uncle, N. M. Pattnaik, for conceiving of the project. We have all jpayne@68: benefited from the discussions amidst the group of people working on this jpayne@68: project. On the particular issue of translation, the help of H. R. Pansari, jpayne@68: A. Nayak, and M. Chand is much appreciated. jpayne@68: jpayne@68:

jpayne@68: The Emacs info browser jpayne@68:

jpayne@68: You can start up Emacs from the command-line by typing “emacs,” or “emacs jpayne@68: <filename>.” It can be started from the menu in some desktops, e.g., on jpayne@68: my GNOME desktop, it is under Main Menu -> Programming -> jpayne@68: Emacs. If you are unfamiliar with Emacs, a tutorial can be started by typing jpayne@68: “C-h t” in an Emacs window, or from the Help item in the menubar at the jpayne@68: top. Emacs makes extensive use of the Control (sometimes labelled as “CTRL” jpayne@68: or “CTL”) and Meta (sometimes labelled as “Edit” or “Alt”) keys. In jpayne@68: Emacs parlance, a hyphenated sequence, such as “C-h” means to press the jpayne@68: Control and ‘h’ key simultaneously, while “C-h t” would mean to press the jpayne@68: Control and ‘h’ key together, release them, and press the ‘t’ key. Similarly, jpayne@68: “M-x” is used to indicate that the Meta and ‘x’ keys should be pressed at jpayne@68: the same time. jpayne@68: jpayne@68:

jpayne@68: The info browser can be started by typing “C-h i” in Emacs. The first time jpayne@68: you do this, it will briefly list some commands available inside the info jpayne@68: browser, and present you with a menu of major topics. Each menu item, or jpayne@68: cross-reference is hyperlinked to the appropriate node, and you can visit that jpayne@68: node either by moving the cursor to the item and pressing Enter, or by jpayne@68: clicking on it with the middle mouse button. To get to the gettext menu items, jpayne@68: you can either scroll down to the line, jpayne@68:

jpayne@68:   * gettext: (gettext).                          GNU gettext utilities.
jpayne@68: 
jpayne@68: and visit that node. Or, as it is several pages down, you can locate it using jpayne@68: “I-search.” Type “C-s” to enter “I-search” which will then prompt you jpayne@68: for a string in the mini-buffer at the bottom of the window. This is an jpayne@68: incremental search, so that Emacs will keep moving you forward through the jpayne@68: buffer as you are entering your search string. If you have reached the last jpayne@68: occurrence of the search string in the current buffer, you will get a message jpayne@68: saying “Failing I-search: ...” on pressing “C-s.” At that point, press jpayne@68: “C-s” again to resume the search at the beginning of the buffer. Likewise, jpayne@68: “C-r” incrementally searches backwards from the present location. jpayne@68: jpayne@68:

jpayne@68: Info nodes are listed in this document with a “::” separator, so jpayne@68: that one can go to the gettext::Creating::Header Entry:: by visiting the jpayne@68: “gettext” node from the main info menu, navigating to the “Creating” jpayne@68: node, and following that to the “Header Entry” node. jpayne@68: jpayne@68:

jpayne@68: A stand-alone info browser, independent of Emacs, is also available on many jpayne@68: systems. Thus, the gettext info page can also be accessed by typing jpayne@68: “info gettext” in a terminal. xinfo is an X application serving as an jpayne@68: info browser, so that if it is installed, typing “xinfo gettext” from the jpayne@68: command line will open a new browser window with the gettext info page. jpayne@68: jpayne@68:

jpayne@68: jpayne@68:

jpayne@68: PO file editors jpayne@68:

jpayne@68: While the yudit editor is adequate for our present purposes, and we are jpayne@68: planning on using that as it is platform-independent, and currently the best jpayne@68: at rendering Oriya. This section describes some features of some editors that jpayne@68: are specialized for editing PO files under Linux. This is still work in jpayne@68: progress, as I am in the process of trying out different editors before jpayne@68: settling on one. The ones considered here are: Emacs in po-mode, poedit, jpayne@68: kbabel, and gtranslator. jpayne@68: jpayne@68:

jpayne@68: Emacs PO mode jpayne@68:

jpayne@68: Emacs should automatically enter po-mode when you load a .po file, as jpayne@68: indicated by “PO” in the modeline at the bottom. The window is made jpayne@68: read-only, so that you can edit the .po file only through special commands. A jpayne@68: description of Emacs po-mode can be found under the gettext::Basics info node, jpayne@68: or type ‘h’ or ‘?’ in a po-mode window for a list of available commands. While jpayne@68: I find Emacs po-mode quite restrictive, this is probably due to unfamiliarity jpayne@68: with it. Its main advantage is that it imposes rigid conformance to the PO jpayne@68: file format, and checks the file format when closing the .po file jpayne@68: buffer. Emacs po-mode is not useful for Oriya translation, as I know of no way jpayne@68: to directly enter Oriya text under Emacs. jpayne@68: jpayne@68:

jpayne@68: poedit jpayne@68:

jpayne@68: XXX: in preparation. jpayne@68: jpayne@68:

jpayne@68: KDE: the kbabel editor jpayne@68:

jpayne@68: kbabel [4] is a more user-friendly and configurable editor than jpayne@68: either of Emacs po-mode or poedit. It is integrated into KDE, and offers jpayne@68: extensive contextual help. Besides support for various PO file features, it jpayne@68: has a plugin framework for dictionaries, that allows consistency checks and jpayne@68: translation suggestions. jpayne@68: jpayne@68:

jpayne@68: GNOME: the gtranslator editor jpayne@68:

jpayne@68: XXX: in preparation. jpayne@68: jpayne@68:

jpayne@68: Bibliography jpayne@68:

1 jpayne@68:
jpayne@68: G. Mohanty, jpayne@68:
A practical primer for using Oriya under Linux, v0.3, jpayne@68:
http://oriya.sarovar.org/docs/getting_started/index.html, 2004, jpayne@68:
Sec. 6.2 describes the xkb layouts for Oriya. jpayne@68: jpayne@68:

2 jpayne@68:
jpayne@68: G. Mohanty, jpayne@68:
A plan for Oriya localization, v0.1, jpayne@68:
http://oriya.sarovar.org/docs/translation_plan/index.html, jpayne@68: 2004. jpayne@68: jpayne@68:

3 jpayne@68:
jpayne@68: Linux Journal article on internationalization, jpayne@68:
https://www.linuxjournal.com/article/3023. jpayne@68: jpayne@68:

4 jpayne@68:
jpayne@68: Features of the kbabel editor, jpayne@68:
http://i18n.kde.org/tools/kbabel/features.html. jpayne@68:
jpayne@68: jpayne@68:

jpayne@68: About this document ... jpayne@68:

jpayne@68: A tutorial on Native Language Support using GNU gettext

jpayne@68: This document was generated using the jpayne@68: LaTeX2HTML translator Version 2002-2-1 (1.70) jpayne@68:

jpayne@68: Copyright © 1993, 1994, 1995, 1996, jpayne@68: Nikos Drakos, jpayne@68: Computer Based Learning Unit, University of Leeds. jpayne@68:
Copyright © 1997, 1998, 1999, jpayne@68: Ross Moore, jpayne@68: Mathematics Department, Macquarie University, Sydney. jpayne@68:

jpayne@68: The command line arguments were:
jpayne@68: latex2html -no_math -html_version 4.0,math,unicode,i18n,tables -split 0 memo jpayne@68:

jpayne@68: The translation was initiated by Gora Mohanty on 2004-07-24 jpayne@68: