This is gettext.info, produced by makeinfo version 4.2 from gettext.texi. INFO-DIR-SECTION GNU Gettext Utilities START-INFO-DIR-ENTRY * gettext: (gettext). GNU gettext utilities. * autopoint: (gettext)autopoint Invocation. Copy gettext infrastructure. * gettextize: (gettext)gettextize Invocation. Prepare a package for gettext. * msgattrib: (gettext)msgattrib Invocation. Select part of a PO file. * msgcat: (gettext)msgcat Invocation. Combine several PO files. * msgcmp: (gettext)msgcmp Invocation. Compare a PO file and template. * msgcomm: (gettext)msgcomm Invocation. Match two PO files. * msgconv: (gettext)msgconv Invocation. Convert PO file to encoding. * msgen: (gettext)msgen Invocation. Create an English PO file. * msgexec: (gettext)msgexec Invocation. Process a PO file. * msgfilter: (gettext)msgfilter Invocation. Pipe a PO file through a filter. * msgfmt: (gettext)msgfmt Invocation. Make MO files out of PO files. * msggrep: (gettext)msggrep Invocation. Select part of a PO file. * msginit: (gettext)msginit Invocation. Create a fresh PO file. * msgmerge: (gettext)msgmerge Invocation. Update a PO file from template. * msgunfmt: (gettext)msgunfmt Invocation. Uncompile MO file into PO file. * msguniq: (gettext)msguniq Invocation. Unify duplicates for PO file. * xgettext: (gettext)xgettext Invocation. Extract strings into a PO file. * ISO639: (gettext)Language Codes. ISO 639 language codes. * ISO3166: (gettext)Country Codes. ISO 3166 country codes. END-INFO-DIR-ENTRY This file provides documentation for GNU `gettext' utilities. It also serves as a reference for the free Translation Project. Copyright (C) 1995, 1996, 1997, 1998, 2001, 2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Foundation.  File: gettext.info, Node: msgfmt Invocation, Next: msgunfmt Invocation, Prev: Binaries, Up: Binaries Invoking the `msgfmt' Program ============================= msgfmt [OPTION] FILENAME.po ... The `msgfmt' programs generates a binary message catalog from a textual translation description. Input file location ------------------- `FILENAME.po ...' `-D DIRECTORY' `--directory=DIRECTORY' Add DIRECTORY to the list of directories. Source files are searched relative to this list of directories. The resulting `.po' file will be written relative to the current directory, though. If an input file is `-', standard input is read. Operation mode -------------- `-j' `--java' Java mode: generate a Java `ResourceBundle' class. `--java2' Like -java, and assume Java2 (JDK 1.2 or higher). `--tcl' Tcl mode: generate a tcl/msgcat `.msg' file. Output file location -------------------- `-o FILE' `--output-file=FILE' Write output to specified file. `--strict' Direct the program to work strictly following the Uniforum/Sun implementation. Currently this only affects the naming of the output file. If this option is not given the name of the output file is the same as the domain name. If the strict Uniforum mode is enabled the suffix `.mo' is added to the file name if it is not already present. We find this behaviour of Sun's implementation rather silly and so by default this mode is _not_ selected. If the output FILE is `-', output is written to standard output. Output file location in Java mode --------------------------------- `-r RESOURCE' `--resource=RESOURCE' Specify the resource name. `-l LOCALE' `--locale=LOCALE' Specify the locale name, either a language specification of the form LL or a combined language and country specification of the form LL_CC. `-d DIRECTORY' Specify the base directory of classes directory hierarchy. The class name is determined by appending the locale name to the resource name, separated with an underscore. The `-d' option is mandatory. The class is written under the specified directory. Output file location in Tcl mode -------------------------------- `-l LOCALE' `--locale=LOCALE' Specify the locale name, either a language specification of the form LL or a combined language and country specification of the form LL_CC. `-d DIRECTORY' Specify the base directory of `.msg' message catalogs. The `-l' and `-d' options are mandatory. The `.msg' file is written in the specified directory. Input file interpretation ------------------------- `-c' `--check' Perform all the checks implied by `--check-format', `--check-header', `--check-domain'. `--check-format' Check language dependent format strings. If the string represents a format string used in a `printf'-like function both strings should have the same number of `%' format specifiers, with matching types. If the flag `c-format' or `possible-c-format' appears in the special comment <#,> for this entry a check is performed. For example, the check will diagnose using `%.*s' against `%s', or `%d' against `%s', or `%d' against `%x'. It can even handle positional parameters. Normally the `xgettext' program automatically decides whether a string is a format string or not. This algorithm is not perfect, though. It might regard a string as a format string though it is not used in a `printf'-like function and so `msgfmt' might report errors where there are none. To solve this problem the programmer can dictate the decision to the `xgettext' program (*note c-format::). The translator should not consider removing the flag from the <#,> line. This "fix" would be reversed again as soon as `msgmerge' is called the next time. `--check-header' Verify presence and contents of the header entry. *Note Header Entry::, for a description of the various fields in the header entry. `--check-domain' Check for conflicts between domain directives and the `--output-file' option `-C' `--check-compatibility' Check that GNU msgfmt behaves like X/Open msgfmt. This will give an error when attempting to use the GNU extensions. `--check-accelerators[=CHAR]' Check presence of keyboard accelerators for menu items. This is based on the convention used in some GUIs that a keyboard accelerator in a menu item string is designated by an immediately preceding `&' character. Sometimes a keyboard accelerator is also called "keyboard mnemonic". This check verifies that if the untranslated string has exactly one `&' character, the translated string has exactly one `&' as well. If this option is given with a CHAR argument, this CHAR should be a non-alphanumeric character and is used as keyboard acceleator mark instead of `&'. `-f' `--use-fuzzy' Use fuzzy entries in output. Note that using this option is usually wrong, because fuzzy messages are exactly those which have not been validated by a human translator. Output details -------------- `-a NUMBER' `--alignment=NUMBER' Align strings to NUMBER bytes (default: 1). `--no-hash' Don't include a hash table in the binary file. Lookup will be more expensive at run time (binary search instead of hash table lookup). Informative output ------------------ `-h' `--help' Display this help and exit. `-V' `--version' Output version information and exit. `--statistics' Print statistics about translations. `-v' `--verbose' Increase verbosity level.  File: gettext.info, Node: msgunfmt Invocation, Next: MO Files, Prev: msgfmt Invocation, Up: Binaries Invoking the `msgunfmt' Program =============================== msgunfmt [OPTION] [FILE]... The `msgunfmt' program converts a binary message catalog to a Uniforum style .po file. Operation mode -------------- `-j' `--java' Java mode: input is a Java `ResourceBundle' class. `--tcl' Tcl mode: input is a tcl/msgcat `.msg' file. Input file location ------------------- `FILE ...' Input .mo files. If no input FILE is given or if it is `-', standard input is read. Input file location in Java mode -------------------------------- `-r RESOURCE' `--resource=RESOURCE' Specify the resource name. `-l LOCALE' `--locale=LOCALE' Specify the locale name, either a language specification of the form LL or a combined language and country specification of the form LL_CC. The class name is determined by appending the locale name to the resource name, separated with an underscore. The class is located using the `CLASSPATH'. Input file location in Tcl mode ------------------------------- `-l LOCALE' `--locale=LOCALE' Specify the locale name, either a language specification of the form LL or a combined language and country specification of the form LL_CC. `-d DIRECTORY' Specify the base directory of `.msg' message catalogs. The `-l' and `-d' options are mandatory. The `.msg' file is located in the specified directory. Output file location -------------------- `-o FILE' `--output-file=FILE' Write output to specified file. The results are written to standard output if no output file is specified or if it is `-'. Output details -------------- `--force-po' Always write an output file even if it contains no message. `-i' `--indent' Write the .po file using indented style. `--strict' Write out a strict Uniforum conforming PO file. Note that this Uniforum format should be avoided because it doesn't support the GNU extensions. `-w NUMBER' `--width=NUMBER' Set the output page width. Long strings in the output files will be split across multiple lines in order to ensure that each line's width (= number of screen columns) is less or equal to the given NUMBER. `--no-wrap' Do not break long message lines. Message lines whose width exceeds the output page width will not be split into several lines. Only file reference lines which are wider than the output page width will be split. `-s' `--sort-output' Generate sorted output. Note that using this option makes it much harder for the translator to understand each message's context. Informative output ------------------ `-h' `--help' Display this help and exit. `-V' `--version' Output version information and exit. `-v' `--verbose' Increase verbosity level.  File: gettext.info, Node: MO Files, Prev: msgunfmt Invocation, Up: Binaries The Format of GNU MO Files ========================== The format of the generated MO files is best described by a picture, which appears below. The first two words serve the identification of the file. The magic number will always signal GNU MO files. The number is stored in the byte order of the generating machine, so the magic number really is two numbers: `0x950412de' and `0xde120495'. The second word describes the current revision of the file format. For now the revision is 0. This might change in future versions, and ensures that the readers of MO files can distinguish new formats from old ones, so that both can be handled correctly. The version is kept separate from the magic number, instead of using different magic numbers for different formats, mainly because `/etc/magic' is not updated often. It might be better to have magic separated from internal format version identification. Follow a number of pointers to later tables in the file, allowing for the extension of the prefix part of MO files without having to recompile programs reading them. This might become useful for later inserting a few flag bits, indication about the charset used, new tables, or other things. Then, at offset O and offset T in the picture, two tables of string descriptors can be found. In both tables, each string descriptor uses two 32 bits integers, one for the string length, another for the offset of the string in the MO file, counting in bytes from the start of the file. The first table contains descriptors for the original strings, and is sorted so the original strings are in increasing lexicographical order. The second table contains descriptors for the translated strings, and is parallel to the first table: to find the corresponding translation one has to access the array slot in the second array with the same index. Having the original strings sorted enables the use of simple binary search, for when the MO file does not contain an hashing table, or for when it is not practical to use the hashing table provided in the MO file. This also has another advantage, as the empty string in a PO file GNU `gettext' is usually _translated_ into some system information attached to that particular MO file, and the empty string necessarily becomes the first in both the original and translated tables, making the system information very easy to find. The size S of the hash table can be zero. In this case, the hash table itself is not contained in the MO file. Some people might prefer this because a precomputed hashing table takes disk space, and does not win _that_ much speed. The hash table contains indices to the sorted array of strings in the MO file. Conflict resolution is done by double hashing. The precise hashing algorithm used is fairly dependent on GNU `gettext' code, and is not documented here. As for the strings themselves, they follow the hash file, and each is terminated with a , and this is not counted in the length which appears in the string descriptor. The `msgfmt' program has an option selecting the alignment for MO file strings. With this option, each string is separately aligned so it starts at an offset which is a multiple of the alignment value. On some RISC machines, a correct alignment will speed things up. Plural forms are stored by letting the plural of the original string follow the singular of the original string, separated through a byte. The length which appears in the string descriptor includes both. However, only the singular of the original string takes part in the hash table lookup. The plural variants of the translation are all stored consecutively, separated through a byte. Here also, the length in the string descriptor includes all of them. Nothing prevents a MO file from having embedded s in strings. However, the program interface currently used already presumes that strings are terminated, so embedded s are somewhat useless. But the MO file format is general enough so other interfaces would be later possible, if for example, we ever want to implement wide characters right in MO files, where bytes may accidently appear. (No, we don't want to have wide characters in MO files. They would make the file unnecessarily large, and the `wchar_t' type being platform dependent, MO files would be platform dependent as well.) This particular issue has been strongly debated in the GNU `gettext' development forum, and it is expectable that MO file format will evolve or change over time. It is even possible that many formats may later be supported concurrently. But surely, we have to start somewhere, and the MO file format described here is a good start. Nothing is cast in concrete, and the format may later evolve fairly easily, so we should feel comfortable with the current approach. byte +------------------------------------------+ 0 | magic number = 0x950412de | | | 4 | file format revision = 0 | | | 8 | number of strings | == N | | 12 | offset of table with original strings | == O | | 16 | offset of table with translation strings | == T | | 20 | size of hashing table | == S | | 24 | offset of hashing table | == H | | . . . (possibly more entries later) . . . | | O | length & offset 0th string ----------------. O + 8 | length & offset 1st string ------------------. ... ... | | O + ((N-1)*8)| length & offset (N-1)th string | | | | | | | T | length & offset 0th translation ---------------. T + 8 | length & offset 1st translation -----------------. ... ... | | | | T + ((N-1)*8)| length & offset (N-1)th translation | | | | | | | | | | | H | start hash table | | | | | ... ... | | | | H + S * 4 | end hash table | | | | | | | | | | | | NUL terminated 0th string <----------------' | | | | | | | | | NUL terminated 1st string <------------------' | | | | | | ... ... | | | | | | | NUL terminated 0th translation <---------------' | | | | | NUL terminated 1st translation <-----------------' | | ... ... | | +------------------------------------------+  File: gettext.info, Node: Users, Next: Programmers, Prev: Binaries, Up: Top The User's View *************** When GNU `gettext' will truly have reached its goal, average users should feel some kind of astonished pleasure, seeing the effect of that strange kind of magic that just makes their own native language appear everywhere on their screens. As for naive users, they would ideally have no special pleasure about it, merely taking their own language for _granted_, and becoming rather unhappy otherwise. So, let's try to describe here how we would like the magic to operate, as we want the users' view to be the simplest, among all ways one could look at GNU `gettext'. All other software engineers: programmers, translators, maintainers, should work together in such a way that the magic becomes possible. This is a long and progressive undertaking, and information is available about the progress of the Translation Project. When a package is distributed, there are two kinds of users: "installers" who fetch the distribution, unpack it, configure it, compile it and install it for themselves or others to use; and "end users" that call programs of the package, once these have been installed at their site. GNU `gettext' is offering magic for both installers and end users. * Menu: * Matrix:: The Current `ABOUT-NLS' Matrix * Installers:: Magic for Installers * End Users:: Magic for End Users  File: gettext.info, Node: Matrix, Next: Installers, Prev: Users, Up: Users The Current `ABOUT-NLS' Matrix ============================== Languages are not equally supported in all packages using GNU `gettext'. To know if some package uses GNU `gettext', one may check the distribution for the `ABOUT-NLS' information file, for some `LL.po' files, often kept together into some `po/' directory, or for an `intl/' directory. Internationalized packages have usually many `LL.po' files, where LL represents the language. *Note End Users:: for a complete description of the format for LL. More generally, a matrix is available for showing the current state of the Translation Project, listing which packages are prepared for multi-lingual messages, and which languages are supported by each. Because this information changes often, this matrix is not kept within this GNU `gettext' manual. This information is often found in file `ABOUT-NLS' from various distributions, but is also as old as the distribution itself. A recent copy of this `ABOUT-NLS' file, containing up-to-date information, should generally be found on the Translation Project sites, and also on most GNU archive sites.  File: gettext.info, Node: Installers, Next: End Users, Prev: Matrix, Up: Users Magic for Installers ==================== By default, packages fully using GNU `gettext', internally, are installed in such a way that they to allow translation of messages. At _configuration_ time, those packages should automatically detect whether the underlying host system already provides the GNU `gettext' functions. If not, the GNU `gettext' library should be automatically prepared and used. Installers may use special options at configuration time for changing this behavior. The command `./configure --with-included-gettext' bypasses system `gettext' to use the included GNU `gettext' instead, while `./configure --disable-nls' produces programs totally unable to translate messages. Internationalized packages have usually many `LL.po' files. Unless translations are disabled, all those available are installed together with the package. However, the environment variable `LINGUAS' may be set, prior to configuration, to limit the installed set. `LINGUAS' should then contain a space separated list of two-letter codes, stating which languages are allowed.  File: gettext.info, Node: End Users, Prev: Installers, Up: Users Magic for End Users =================== We consider here those packages using GNU `gettext' internally, and for which the installers did not disable translation at _configure_ time. Then, users only have to set the `LANG' environment variable to the appropriate `LL_CC' combination prior to using the programs in the package. *Note Matrix::. For example, let's presume a German site. At the shell prompt, users merely have to execute `setenv LANG de_DE' (in `csh') or `export LANG; LANG=de_DE' (in `sh'). They could even do this from their `.login' or `.profile' file.  File: gettext.info, Node: Programmers, Next: Translators, Prev: Users, Up: Top The Programmer's View ********************* One aim of the current message catalog implementation provided by GNU `gettext' was to use the system's message catalog handling, if the installer wishes to do so. So we perhaps should first take a look at the solutions we know about. The people in the POSIX committee did not manage to agree on one of the semi-official standards which we'll describe below. In fact they couldn't agree on anything, so they decided only to include an example of an interface. The major Unix vendors are split in the usage of the two most important specifications: X/Open's catgets vs. Uniforum's gettext interface. We'll describe them both and later explain our solution of this dilemma. * Menu: * catgets:: About `catgets' * gettext:: About `gettext' * Comparison:: Comparing the two interfaces * Using libintl.a:: Using libintl.a in own programs * gettext grok:: Being a `gettext' grok * Temp Programmers:: Temporary Notes for the Programmers Chapter  File: gettext.info, Node: catgets, Next: gettext, Prev: Programmers, Up: Programmers About `catgets' =============== The `catgets' implementation is defined in the X/Open Portability Guide, Volume 3, XSI Supplementary Definitions, Chapter 5. But the process of creating this standard seemed to be too slow for some of the Unix vendors so they created their implementations on preliminary versions of the standard. Of course this leads again to problems while writing platform independent programs: even the usage of `catgets' does not guarantee a unique interface. Another, personal comment on this that only a bunch of committee members could have made this interface. They never really tried to program using this interface. It is a fast, memory-saving implementation, an user can happily live with it. But programmers hate it (at least I and some others do...) But we must not forget one point: after all the trouble with transfering the rights on Unix(tm) they at last came to X/Open, the very same who published this specification. This leads me to making the prediction that this interface will be in future Unix standards (e.g. Spec1170) and therefore part of all Unix implementation (implementations, which are _allowed_ to wear this name). * Menu: * Interface to catgets:: The interface * Problems with catgets:: Problems with the `catgets' interface?!  File: gettext.info, Node: Interface to catgets, Next: Problems with catgets, Prev: catgets, Up: catgets The Interface ------------- The interface to the `catgets' implementation consists of three functions which correspond to those used in file access: `catopen' to open the catalog for using, `catgets' for accessing the message tables, and `catclose' for closing after work is done. Prototypes for the functions and the needed definitions are in the `' header file. `catopen' is used like in this: nl_catd catd = catopen ("catalog_name", 0); The function takes as the argument the name of the catalog. This usual refers to the name of the program or the package. The second parameter is not further specified in the standard. I don't even know whether it is implemented consistently among various systems. So the common advice is to use `0' as the value. The return value is a handle to the message catalog, equivalent to handles to file returned by `open'. This handle is of course used in the `catgets' function which can be used like this: char *translation = catgets (catd, set_no, msg_id, "original string"); The first parameter is this catalog descriptor. The second parameter specifies the set of messages in this catalog, in which the message described by `msg_id' is obtained. `catgets' therefore uses a three-stage addressing: catalog name => set number => message ID => translation The fourth argument is not used to address the translation. It is given as a default value in case when one of the addressing stages fail. One important thing to remember is that although the return type of catgets is `char *' the resulting string _must not_ be changed. It should better be `const char *', but the standard is published in 1988, one year before ANSI C. The last of these function functions is used and behaves as expected: catclose (catd); After this no `catgets' call using the descriptor is legal anymore.  File: gettext.info, Node: Problems with catgets, Prev: Interface to catgets, Up: catgets Problems with the `catgets' Interface?! --------------------------------------- Now that this description seemed to be really easy -- where are the problems we speak of? In fact the interface could be used in a reasonable way, but constructing the message catalogs is a pain. The reason for this lies in the third argument of `catgets': the unique message ID. This has to be a numeric value for all messages in a single set. Perhaps you could imagine the problems keeping such a list while changing the source code. Add a new message here, remove one there. Of course there have been developed a lot of tools helping to organize this chaos but one as the other fails in one aspect or the other. We don't want to say that the other approach has no problems but they are far more easy to manage.  File: gettext.info, Node: gettext, Next: Comparison, Prev: catgets, Up: Programmers About `gettext' =============== The definition of the `gettext' interface comes from a Uniforum proposal and it is followed by at least one major Unix vendor (Sun) in its last developments. It is not specified in any official standard, though. The main points about this solution is that it does not follow the method of normal file handling (open-use-close) and that it does not burden the programmer so many task, especially the unique key handling. Of course here also a unique key is needed, but this key is the message itself (how long or short it is). See *Note Comparison:: for a more detailed comparison of the two methods. The following section contains a rather detailed description of the interface. We make it that detailed because this is the interface we chose for the GNU `gettext' Library. Programmers interested in using this library will be interested in this description. * Menu: * Interface to gettext:: The interface * Ambiguities:: Solving ambiguities * Locating Catalogs:: Locating message catalog files * Charset conversion:: How to request conversion to Unicode * Plural forms:: Additional functions for handling plurals * GUI program problems:: Another technique for solving ambiguities * Optimized gettext:: Optimization of the *gettext functions  File: gettext.info, Node: Interface to gettext, Next: Ambiguities, Prev: gettext, Up: gettext The Interface ------------- The minimal functionality an interface must have is a) to select a domain the strings are coming from (a single domain for all programs is not reasonable because its construction and maintenance is difficult, perhaps impossible) and b) to access a string in a selected domain. This is principally the description of the `gettext' interface. It has a global domain which unqualified usages reference. Of course this domain is selectable by the user. char *textdomain (const char *domain_name); This provides the possibility to change or query the current status of the current global domain of the `LC_MESSAGE' category. The argument is a null-terminated string, whose characters must be legal in the use in filenames. If the DOMAIN_NAME argument is `NULL', the function returns the current value. If no value has been set before, the name of the default domain is returned: _messages_. Please note that although the return value of `textdomain' is of type `char *' no changing is allowed. It is also important to know that no checks of the availability are made. If the name is not available you will see this by the fact that no translations are provided. To use a domain set by `textdomain' the function char *gettext (const char *msgid); is to be used. This is the simplest reasonable form one can imagine. The translation of the string MSGID is returned if it is available in the current domain. If not available the argument itself is returned. If the argument is `NULL' the result is undefined. One things which should come into mind is that no explicit dependency to the used domain is given. The current value of the domain for the `LC_MESSAGES' locale is used. If this changes between two executions of the same `gettext' call in the program, both calls reference a different message catalog. For the easiest case, which is normally used in internationalized packages, once at the beginning of execution a call to `textdomain' is issued, setting the domain to a unique name, normally the package name. In the following code all strings which have to be translated are filtered through the gettext function. That's all, the package speaks your language.  File: gettext.info, Node: Ambiguities, Next: Locating Catalogs, Prev: Interface to gettext, Up: gettext Solving Ambiguities ------------------- While this single name domain works well for most applications there might be the need to get translations from more than one domain. Of course one could switch between different domains with calls to `textdomain', but this is really not convenient nor is it fast. A possible situation could be one case subject to discussion during this writing: all error messages of functions in the set of common used functions should go into a separate domain `error'. By this mean we would only need to translate them once. Another case are messages from a library, as these _have_ to be independent of the current domain set by the application. For this reasons there are two more functions to retrieve strings: char *dgettext (const char *domain_name, const char *msgid); char *dcgettext (const char *domain_name, const char *msgid, int category); Both take an additional argument at the first place, which corresponds to the argument of `textdomain'. The third argument of `dcgettext' allows to use another locale but `LC_MESSAGES'. But I really don't know where this can be useful. If the DOMAIN_NAME is `NULL' or CATEGORY has an value beside the known ones, the result is undefined. It should also be noted that this function is not part of the second known implementation of this function family, the one found in Solaris. A second ambiguity can arise by the fact, that perhaps more than one domain has the same name. This can be solved by specifying where the needed message catalog files can be found. char *bindtextdomain (const char *domain_name, const char *dir_name); Calling this function binds the given domain to a file in the specified directory (how this file is determined follows below). Especially a file in the systems default place is not favored against the specified file anymore (as it would be by solely using `textdomain'). A `NULL' pointer for the DIR_NAME parameter returns the binding associated with DOMAIN_NAME. If DOMAIN_NAME itself is `NULL' nothing happens and a `NULL' pointer is returned. Here again as for all the other functions is true that none of the return value must be changed! It is important to remember that relative path names for the DIR_NAME parameter can be trouble. Since the path is always computed relative to the current directory different results will be achieved when the program executes a `chdir' command. Relative paths should always be avoided to avoid dependencies and unreliabilities.  File: gettext.info, Node: Locating Catalogs, Next: Charset conversion, Prev: Ambiguities, Up: gettext Locating Message Catalog Files ------------------------------ Because many different languages for many different packages have to be stored we need some way to add these information to file message catalog files. The way usually used in Unix environments is have this encoding in the file name. This is also done here. The directory name given in `bindtextdomain's second argument (or the default directory), followed by the value and name of the locale and the domain name are concatenated: DIR_NAME/LOCALE/LC_CATEGORY/DOMAIN_NAME.mo The default value for DIR_NAME is system specific. For the GNU library, and for packages adhering to its conventions, it's: /usr/local/share/locale LOCALE is the value of the locale whose name is this `LC_CATEGORY'. For `gettext' and `dgettext' this `LC_CATEGORY' is always `LC_MESSAGES'.(1) The value of the locale is determined through `setlocale (LC_CATEGORY, NULL)'. (2) `dcgettext' specifies the locale category by the third argument. ---------- Footnotes ---------- (1) Some system, eg Ultrix, don't have `LC_MESSAGES'. Here we use a more or less arbitrary value for it, namely 1729, the smallest positive integer which can be represented in two different ways as the sum of two cubes. (2) When the system does not support `setlocale' its behavior in setting the locale values is simulated by looking at the environment variables.  File: gettext.info, Node: Charset conversion, Next: Plural forms, Prev: Locating Catalogs, Up: gettext How to specify the output character set `gettext' uses ------------------------------------------------------ `gettext' not only looks up a translation in a message catalog. It also converts the translation on the fly to the desired output character set. This is useful if the user is working in a different character set than the translator who created the message catalog, because it avoids distributing variants of message catalogs which differ only in the character set. The output character set is, by default, the value of `nl_langinfo (CODESET)', which depends on the `LC_CTYPE' part of the current locale. But programs which store strings in a locale independent way (e.g. UTF-8) can request that `gettext' and related functions return the translations in that encoding, by use of the `bind_textdomain_codeset' function. Note that the MSGID argument to `gettext' is not subject to character set conversion. Also, when `gettext' does not find a translation for MSGID, it returns MSGID unchanged - independently of the current output character set. It is therefore recommended that all MSGIDs be US-ASCII strings. - Function: char * bind_textdomain_codeset (const char *DOMAINNAME, const char *CODESET) The `bind_textdomain_codeset' function can be used to specify the output character set for message catalogs for domain DOMAINNAME. The CODESET argument must be a valid codeset name which can be used for the `iconv_open' function, or a null pointer. If the CODESET parameter is the null pointer, `bind_textdomain_codeset' returns the currently selected codeset for the domain with the name DOMAINNAME. It returns `NULL' if no codeset has yet been selected. The `bind_textdomain_codeset' function can be used several times. If used multiple times with the same DOMAINNAME argument, the later call overrides the settings made by the earlier one. The `bind_textdomain_codeset' function returns a pointer to a string containing the name of the selected codeset. The string is allocated internally in the function and must not be changed by the user. If the system went out of core during the execution of `bind_textdomain_codeset', the return value is `NULL' and the global variable ERRNO is set accordingly.  File: gettext.info, Node: Plural forms, Next: GUI program problems, Prev: Charset conversion, Up: gettext Additional functions for plural forms ------------------------------------- The functions of the `gettext' family described so far (and all the `catgets' functions as well) have one problem in the real world which have been neglected completely in all existing approaches. What is meant here is the handling of plural forms. Looking through Unix source code before the time anybody thought about internationalization (and, sadly, even afterwards) one can often find code similar to the following: printf ("%d file%s deleted", n, n == 1 ? "" : "s"); After the first complaints from people internationalizing the code people either completely avoided formulations like this or used strings like `"file(s)"'. Both look unnatural and should be avoided. First tries to solve the problem correctly looked like this: if (n == 1) printf ("%d file deleted", n); else printf ("%d files deleted", n); But this does not solve the problem. It helps languages where the plural form of a noun is not simply constructed by adding an `s' but that is all. Once again people fell into the trap of believing the rules their language is using are universal. But the handling of plural forms differs widely between the language families. For example, Rafal Maszkowski `' reports: In Polish we use e.g. plik (file) this way: 1 plik 2,3,4 pliki 5-21 pliko'w 22-24 pliki 25-31 pliko'w and so on (o' means 8859-2 oacute which should be rather okreska, similar to aogonek). There are two things which can differ between languages (and even inside language families); * The form how plural forms are built differs. This is a problem with languages which have many irregularities. German, for instance, is a drastic case. Though English and German are part of the same language family (Germanic), the almost regular forming of plural noun forms (appending an `s') is hardly found in German. * The number of plural forms differ. This is somewhat surprising for those who only have experiences with Romanic and Germanic languages since here the number is the same (there are two). But other language families have only one form or many forms. More information on this in an extra section. The consequence of this is that application writers should not try to solve the problem in their code. This would be localization since it is only usable for certain, hardcoded language environments. Instead the extended `gettext' interface should be used. These extra functions are taking instead of the one key string two strings and a numerical argument. The idea behind this is that using the numerical argument and the first string as a key, the implementation can select using rules specified by the translator the right plural form. The two string arguments then will be used to provide a return value in case no message catalog is found (similar to the normal `gettext' behavior). In this case the rules for Germanic language is used and it is assumed that the first string argument is the singular form, the second the plural form. This has the consequence that programs without language catalogs can display the correct strings only if the program itself is written using a Germanic language. This is a limitation but since the GNU C library (as well as the GNU `gettext' package) are written as part of the GNU package and the coding standards for the GNU project require program being written in English, this solution nevertheless fulfills its purpose. - Function: char * ngettext (const char *MSGID1, const char *MSGID2, unsigned long int N) The `ngettext' function is similar to the `gettext' function as it finds the message catalogs in the same way. But it takes two extra arguments. The MSGID1 parameter must contain the singular form of the string to be converted. It is also used as the key for the search in the catalog. The MSGID2 parameter is the plural form. The parameter N is used to determine the plural form. If no message catalog is found MSGID1 is returned if `n == 1', otherwise `msgid2'. An example for the use of this function is: printf (ngettext ("%d file removed", "%d files removed", n), n); Please note that the numeric value N has to be passed to the `printf' function as well. It is not sufficient to pass it only to `ngettext'. - Function: char * dngettext (const char *DOMAIN, const char *MSGID1, const char *MSGID2, unsigned long int N) The `dngettext' is similar to the `dgettext' function in the way the message catalog is selected. The difference is that it takes two extra parameter to provide the correct plural form. These two parameters are handled in the same way `ngettext' handles them. - Function: char * dcngettext (const char *DOMAIN, const char *MSGID1, const char *MSGID2, unsigned long int N, int CATEGORY) The `dcngettext' is similar to the `dcgettext' function in the way the message catalog is selected. The difference is that it takes two extra parameter to provide the correct plural form. These two parameters are handled in the same way `ngettext' handles them. Now, how do these functions solve the problem of the plural forms? Without the input of linguists (which was not available) it was not possible to determine whether there are only a few different forms in which plural forms are formed or whether the number can increase with every new supported language. Therefore the solution implemented is to allow the translator to specify the rules of how to select the plural form. Since the formula varies with every language this is the only viable solution except for hardcoding the information in the code (which still would require the possibility of extensions to not prevent the use of new languages). The information about the plural form selection has to be stored in the header entry of the PO file (the one with the empty `msgid' string). The plural form information looks like this: Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1; The `nplurals' value must be a decimal number which specifies how many different plural forms exist for this language. The string following `plural' is an expression which is using the C language syntax. Exceptions are that no negative numbers are allowed, numbers must be decimal, and the only variable allowed is `n'. This expression will be evaluated whenever one of the functions `ngettext', `dngettext', or `dcngettext' is called. The numeric value passed to these functions is then substituted for all uses of the variable `n' in the expression. The resulting value then must be greater or equal to zero and smaller than the value given as the value of `nplurals'. The following rules are known at this point. The language with families are listed. But this does not necessarily mean the information can be generalized for the whole family (as can be easily seen in the table below).(1) Only one form: Some languages only require one single form. There is no distinction between the singular and plural form. An appropriate header entry would look like this: Plural-Forms: nplurals=1; plural=0; Languages with this property include: Finno-Ugric family Hungarian Asian family Japanese, Korean Turkic/Altaic family Turkish Two forms, singular used for one only This is the form used in most existing programs since it is what English is using. A header entry would look like this: Plural-Forms: nplurals=2; plural=n != 1; (Note: this uses the feature of C expressions that boolean expressions have to value zero or one.) Languages with this property include: Germanic family Danish, Dutch, English, German, Norwegian, Swedish Finno-Ugric family Estonian, Finnish Latin/Greek family Greek Semitic family Hebrew Romanic family Italian, Portuguese, Spanish Artificial Esperanto Two forms, singular used for zero and one Exceptional case in the language family. The header entry would be: Plural-Forms: nplurals=2; plural=n>1; Languages with this property include: Romanic family French, Brazilian Portuguese Three forms, special case for zero The header entry would be: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; Languages with this property include: Baltic family Latvian Three forms, special cases for one and two The header entry would be: Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; Languages with this property include: Celtic Gaeilge (Irish) Three forms, special case for numbers ending in 1[2-9] The header entry would look like this: Plural-Forms: nplurals=3; \ plural=n%10==1 && n%100!=11 ? 0 : \ n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; Languages with this property include: Baltic family Lithuanian Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4] The header entry would look like this: Plural-Forms: nplurals=3; \ plural=n%10==1 && n%100!=11 ? 0 : \ n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; Languages with this property include: Slavic family Croatian, Czech, Russian, Slovak, Ukrainian Three forms, special case for one and some numbers ending in 2, 3, or 4 The header entry would look like this: Plural-Forms: nplurals=3; \ plural=n==1 ? 0 : \ n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; Languages with this property include: Slavic family Polish Four forms, special case for one and all numbers ending in 02, 03, or 04 The header entry would look like this: Plural-Forms: nplurals=4; \ plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; Languages with this property include: Slavic family Slovenian ---------- Footnotes ---------- (1) Additions are welcome. Send appropriate information to .