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: | [Top] | jpayne@68:[Contents] | jpayne@68:[Index] | jpayne@68:[ ? ] | jpayne@68:
While the presentation of gettext
focuses mostly on C and
jpayne@68: implicitly applies to C++ as well, its scope is far broader than that:
jpayne@68: Many programming languages, scripting languages and other textual data
jpayne@68: like GUI resources or package descriptions can make use of the gettext
jpayne@68: approach.
jpayne@68:
All programming and scripting languages that have the notion of strings
jpayne@68: are eligible to supporting gettext
. Supporting gettext
jpayne@68: means the following:
jpayne@68:
gettext
would do, but a shorthand
jpayne@68: syntax helps keeping the legibility of internationalized programs. For
jpayne@68: example, in C we use the syntax _("string")
, and in GNU awk we use
jpayne@68: the shorthand _"string"
.
jpayne@68:
jpayne@68: gettext
function, or performs equivalent
jpayne@68: processing.
jpayne@68:
jpayne@68: ngettext
,
jpayne@68: dcgettext
, dcngettext
available from within the language.
jpayne@68: These functions are less often used, but are nevertheless necessary for
jpayne@68: particular purposes: ngettext
for correct plural handling, and
jpayne@68: dcgettext
and dcngettext
for obeying other locale-related
jpayne@68: environment variables than LC_MESSAGES
, such as LC_TIME
or
jpayne@68: LC_MONETARY
. For these latter functions, you need to make the
jpayne@68: LC_*
constants, available in the C header <locale.h>
,
jpayne@68: referenceable from within the language, usually either as enumeration
jpayne@68: values or as strings.
jpayne@68:
jpayne@68: textdomain
function available from within the
jpayne@68: language, or by introducing a magic variable called TEXTDOMAIN
.
jpayne@68: Similarly, you should allow the programmer to designate where to search
jpayne@68: for message catalogs, by providing access to the bindtextdomain
jpayne@68: function or — on native Windows platforms — to the wbindtextdomain
jpayne@68: function.
jpayne@68:
jpayne@68: setlocale (LC_ALL, "")
call during
jpayne@68: the startup of your language runtime, or allow the programmer to do so.
jpayne@68: Remember that gettext will act as a no-op if the LC_MESSAGES
and
jpayne@68: LC_CTYPE
locale categories are not both set.
jpayne@68:
jpayne@68: xgettext
program is being
jpayne@68: extended to support very different programming languages. Please
jpayne@68: contact the GNU gettext
maintainers to help them doing this.
jpayne@68: The GNU gettext
maintainers will need from you a formal
jpayne@68: description of the lexical structure of source files. It should
jpayne@68: answer the questions:
jpayne@68: Based on this description, the GNU gettext
maintainers
jpayne@68: can add support to xgettext
.
jpayne@68:
If the string extractor is best integrated into your language's parser,
jpayne@68: GNU xgettext
can function as a front end to your string extractor.
jpayne@68:
gettext
manual will be extended to
jpayne@68: include a pointer to this documentation.
jpayne@68: Based on this, the GNU gettext
maintainers can add a format string
jpayne@68: equivalence checker to msgfmt
, so that translators get told
jpayne@68: immediately when they have made a mistake during the translation of a
jpayne@68: format string.
jpayne@68:
gettext
, but the programs should be portable
jpayne@68: across implementations, you should provide a no-i18n emulation, that
jpayne@68: makes the other implementations accept programs written for yours,
jpayne@68: without actually translating the strings.
jpayne@68:
jpayne@68: gettext
maintainers, so they can add support for
jpayne@68: your language to ‘po-mode.el’.
jpayne@68: On the implementation side, two approaches are possible, with jpayne@68: different effects on portability and copyright: jpayne@68:
jpayne@68:gettext
functions if they are found in
jpayne@68: the C library. For example, an autoconf test for gettext()
and
jpayne@68: ngettext()
will detect this situation. For the moment, this test
jpayne@68: will succeed on GNU systems and on Solaris 11 platforms. No severe
jpayne@68: copyright restrictions apply, except if you want to distribute statically
jpayne@68: linked binaries.
jpayne@68:
jpayne@68: gettext
functionality.
jpayne@68: This has the advantage of full portability and no copyright
jpayne@68: restrictions, but also the drawback that you have to reimplement the GNU
jpayne@68: gettext
features (such as the LANGUAGE
environment
jpayne@68: variable, the locale aliases database, the automatic charset conversion,
jpayne@68: and plural handling).
jpayne@68: For the programmer, the general procedure is the same as for the C
jpayne@68: language. The Emacs PO mode marking supports other languages, and the GNU
jpayne@68: xgettext
string extractor recognizes other languages based on the
jpayne@68: file extension or a command-line option. In some languages,
jpayne@68: setlocale
is not needed because it is already performed by the
jpayne@68: underlying language runtime.
jpayne@68:
The translator works exactly as in the C language case. The only jpayne@68: difference is that when translating format strings, she has to be aware jpayne@68: of the language's particular syntax for positional arguments in format jpayne@68: strings. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68:C format strings are described in POSIX (IEEE P1003.1 2001), section jpayne@68: XSH 3 fprintf(), jpayne@68: http://www.opengroup.org/onlinepubs/007904975/functions/fprintf.html. jpayne@68: See also the fprintf() manual page, jpayne@68: http://www.linuxvalley.it/encyclopedia/ldp/manpage/man3/printf.3.php, jpayne@68: http://informatik.fh-wuerzburg.de/student/i510/man/printf.html. jpayne@68:
jpayne@68:Although format strings with positions that reorder arguments, such as jpayne@68:
jpayne@68:"Only %2$d bytes free on '%1$s'." jpayne@68: |
which is semantically equivalent to jpayne@68:
jpayne@68:"'%s' has only %d bytes free." jpayne@68: |
are a POSIX/XSI feature and not specified by ISO C 99, translators can rely
jpayne@68: on this reordering ability: On the few platforms where printf()
,
jpayne@68: fprintf()
etc. don't support this feature natively, ‘libintl.a’
jpayne@68: or ‘libintl.so’ provides replacement functions, and GNU <libintl.h>
jpayne@68: activates these replacement functions automatically.
jpayne@68:
As a special feature for Farsi (Persian) and maybe Arabic, translators can
jpayne@68: insert an ‘I’ flag into numeric format directives. For example, the
jpayne@68: translation of "%d"
can be "%Id"
. The effect of this flag,
jpayne@68: on systems with GNU libc
, is that in the output, the ASCII digits are
jpayne@68: replaced with the ‘outdigits’ defined in the LC_CTYPE
locale
jpayne@68: category. On other systems, the gettext
function removes this flag,
jpayne@68: so that it has no effect.
jpayne@68:
Note that the programmer should not put this flag into the jpayne@68: untranslated string. (Putting the ‘I’ format directive flag into an jpayne@68: msgid string would lead to undefined behaviour on platforms without jpayne@68: glibc when NLS is disabled.) jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Objective C format strings are like C format strings. They support an
jpayne@68: additional format directive: "%@", which when executed consumes an argument
jpayne@68: of type Object *
.
jpayne@68:
C++ format strings are described in ISO C++ 20, namely in jpayne@68: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4861.pdf, jpayne@68: section 20.20.2 Format string [format.string]. jpayne@68:
jpayne@68:An easier-to-read description is found at jpayne@68: https://en.cppreference.com/w/cpp/utility/format/format#Parameters and jpayne@68: https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:There are two kinds of format strings in Python: those acceptable to
jpayne@68: the Python built-in format operator %
, labelled as
jpayne@68: ‘python-format’, and those acceptable to the format
method
jpayne@68: of the ‘str’ object.
jpayne@68:
Python %
format strings are described in
jpayne@68: Python Library reference /
jpayne@68: 5. Built-in Types /
jpayne@68: 5.6. Sequence Types /
jpayne@68: 5.6.2. String Formatting Operations.
jpayne@68: https://docs.python.org/2/library/stdtypes.html#string-formatting-operations.
jpayne@68:
Python brace format strings are described in PEP 3101 – Advanced jpayne@68: String Formatting, https://www.python.org/dev/peps/pep-3101/. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:There are two kinds of format strings in Java: those acceptable to the
jpayne@68: MessageFormat.format
function, labelled as ‘java-format’,
jpayne@68: and those acceptable to the String.format
and
jpayne@68: PrintStream.printf
functions, labelled as ‘java-printf-format’.
jpayne@68:
Java format strings are described in the JDK documentation for class
jpayne@68: java.text.MessageFormat
,
jpayne@68: https://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html.
jpayne@68: See also the ICU documentation
jpayne@68: http://icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html.
jpayne@68:
Java printf
format strings are described in the JDK documentation
jpayne@68: for class java.util.Formatter
,
jpayne@68: https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html.
jpayne@68:
C# format strings are described in the .NET documentation for class
jpayne@68: System.String
and in
jpayne@68: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpConFormattingOverview.asp.
jpayne@68:
Although JavaScript specification itself does not define any format
jpayne@68: strings, many JavaScript implementations provide printf-like
jpayne@68: functions. xgettext
understands a set of common format strings
jpayne@68: used in popular JavaScript implementations including Gjs, Seed, and
jpayne@68: Node.JS. In such a format string, a directive starts with ‘%’
jpayne@68: and is finished by a specifier: ‘%’ denotes a literal percent
jpayne@68: sign, ‘c’ denotes a character, ‘s’ denotes a string,
jpayne@68: ‘b’, ‘d’, ‘o’, ‘x’, ‘X’ denote an integer,
jpayne@68: ‘f’ denotes floating-point number, ‘j’ denotes a JSON
jpayne@68: object.
jpayne@68:
Scheme format strings are documented in the SLIB manual, section jpayne@68: Format Specification. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Lisp format strings are described in the Common Lisp HyperSpec, jpayne@68: chapter 22.3 Formatted Output, jpayne@68: http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_22-3.html. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Emacs Lisp format strings are documented in the Emacs Lisp reference, jpayne@68: section Formatting Strings, jpayne@68: https://www.gnu.org/manual/elisp-manual-21-2.8/html_chapter/elisp_4.html#SEC75. jpayne@68: Note that as of version 21, XEmacs supports numbered argument specifications jpayne@68: in format strings while FSF Emacs doesn't. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:librep format strings are documented in the librep manual, section jpayne@68: Formatted Output, jpayne@68: http://librep.sourceforge.net/librep-manual.html#Formatted%20Output, jpayne@68: http://www.gwinnup.org/research/docs/librep.html#SEC122. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Ruby format strings are described in the documentation of the Ruby
jpayne@68: functions format
and sprintf
, in
jpayne@68: https://ruby-doc.org/core-2.7.1/Kernel.html#method-i-sprintf.
jpayne@68:
There are two kinds of format strings in Ruby: jpayne@68:
%n$
syntax. Note
jpayne@68: that if one argument uses this syntax, all must use this syntax.
jpayne@68: %<name>
. Note that %{name}
is
jpayne@68: equivalent to %<name>s
.
jpayne@68: Shell format strings, as supported by GNU gettext and the ‘envsubst’
jpayne@68: program, are strings with references to shell variables in the form
jpayne@68: $variable
or ${variable}
. References of the form
jpayne@68: ${variable-default}
,
jpayne@68: ${variable:-default}
,
jpayne@68: ${variable=default}
,
jpayne@68: ${variable:=default}
,
jpayne@68: ${variable+replacement}
,
jpayne@68: ${variable:+replacement}
,
jpayne@68: ${variable?ignored}
,
jpayne@68: ${variable:?ignored}
,
jpayne@68: that would be valid inside shell scripts, are not supported. The
jpayne@68: variable names must consist solely of alphanumeric or underscore
jpayne@68: ASCII characters, not start with a digit and be nonempty; otherwise such
jpayne@68: a variable reference is ignored.
jpayne@68:
awk format strings are described in the gawk documentation, section jpayne@68: Printf, jpayne@68: https://www.gnu.org/manual/gawk/html_node/Printf.html#Printf. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Lua format strings are described in the Lua reference manual, section String Manipulation, jpayne@68: https://www.lua.org/manual/5.1/manual.html#pdf-string.format. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Object Pascal format strings are described in the documentation of the jpayne@68: Free Pascal runtime library, section Format, jpayne@68: https://www.freepascal.org/docs-html/rtl/sysutils/format.html. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Smalltalk format strings are described in the GNU Smalltalk documentation,
jpayne@68: class CharArray
, methods ‘bindWith:’ and
jpayne@68: ‘bindWithArguments:’.
jpayne@68: https://www.gnu.org/software/smalltalk/gst-manual/gst_68.html#SEC238.
jpayne@68: In summary, a directive starts with ‘%’ and is followed by ‘%’
jpayne@68: or a nonzero digit (‘1’ to ‘9’).
jpayne@68:
Qt format strings are described in the documentation of the QString class jpayne@68: file:/usr/lib/qt-4.3.0/doc/html/qstring.html. jpayne@68: In summary, a directive consists of a ‘%’ followed by a digit. The same jpayne@68: directive cannot occur more than once in a format string. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Qt format strings are described in the documentation of the QObject::tr method jpayne@68: file:/usr/lib/qt-4.3.0/doc/html/qobject.html. jpayne@68: In summary, the only allowed directive is ‘%n’. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:KDE 4 format strings are defined as follows: jpayne@68: A directive consists of a ‘%’ followed by a non-zero decimal number. jpayne@68: If a ‘%n’ occurs in a format strings, all of ‘%1’, ..., ‘%(n-1)’ jpayne@68: must occur as well, except possibly one of them. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:KUIT (KDE User Interface Text) is compatible with KDE 4 format strings, jpayne@68: while it also allows programmers to add semantic information to a format jpayne@68: string, through XML markup tags. For example, if the first format jpayne@68: directive in a string is a filename, programmers could indicate that jpayne@68: with a ‘filename’ tag, like ‘<filename>%1</filename>’. jpayne@68:
jpayne@68:KUIT format strings are described in jpayne@68: https://api.kde.org/frameworks/ki18n/html/prg_guide.html#kuit_markup. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Boost format strings are described in the documentation of the
jpayne@68: boost::format
class, at
jpayne@68: https://www.boost.org/libs/format/doc/format.html.
jpayne@68: In summary, a directive has either the same syntax as in a C format string,
jpayne@68: such as ‘%1$+5d’, or may be surrounded by vertical bars, such as
jpayne@68: ‘%|1$+5d|’ or ‘%|1$+5|’, or consists of just an argument number
jpayne@68: between percent signs, such as ‘%1%’.
jpayne@68:
Tcl format strings are described in the ‘format.n’ manual page, jpayne@68: http://www.scriptics.com/man/tcl8.3/TclCmd/format.htm. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:There are two kinds of format strings in Perl: those acceptable to the
jpayne@68: Perl built-in function printf
, labelled as ‘perl-format’,
jpayne@68: and those acceptable to the libintl-perl
function __x
,
jpayne@68: labelled as ‘perl-brace-format’.
jpayne@68:
Perl printf
format strings are described in the sprintf
jpayne@68: section of ‘man perlfunc’.
jpayne@68:
Perl brace format strings are described in the jpayne@68: ‘Locale::TextDomain(3pm)’ manual page of the CPAN package jpayne@68: libintl-perl. In brief, Perl format uses placeholders put between jpayne@68: braces (‘{’ and ‘}’). The placeholder must have the syntax jpayne@68: of simple identifiers. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:PHP format strings are described in the documentation of the PHP function
jpayne@68: sprintf
, in ‘phpdoc/manual/function.sprintf.html’ or
jpayne@68: http://www.php.net/manual/en/function.sprintf.php.
jpayne@68:
These format strings are used inside the GCC sources. In such a format jpayne@68: string, a directive starts with ‘%’, is optionally followed by a jpayne@68: size specifier ‘l’, an optional flag ‘+’, another optional flag jpayne@68: ‘#’, and is finished by a specifier: ‘%’ denotes a literal jpayne@68: percent sign, ‘c’ denotes a character, ‘s’ denotes a string, jpayne@68: ‘i’ and ‘d’ denote an integer, ‘o’, ‘u’, ‘x’ jpayne@68: denote an unsigned integer, ‘.*s’ denotes a string preceded by a jpayne@68: width specification, ‘H’ denotes a ‘location_t *’ pointer, jpayne@68: ‘D’ denotes a general declaration, ‘F’ denotes a function jpayne@68: declaration, ‘T’ denotes a type, ‘A’ denotes a function argument, jpayne@68: ‘C’ denotes a tree code, ‘E’ denotes an expression, ‘L’ jpayne@68: denotes a programming language, ‘O’ denotes a binary operator, jpayne@68: ‘P’ denotes a function parameter, ‘Q’ denotes an assignment jpayne@68: operator, ‘V’ denotes a const/volatile qualifier. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:These format strings are used inside the GNU Fortran Compiler sources, jpayne@68: that is, the Fortran frontend in the GCC sources. In such a format jpayne@68: string, a directive starts with ‘%’ and is finished by a jpayne@68: specifier: ‘%’ denotes a literal percent sign, ‘C’ denotes the jpayne@68: current source location, ‘L’ denotes a source location, ‘c’ jpayne@68: denotes a character, ‘s’ denotes a string, ‘i’ and ‘d’ jpayne@68: denote an integer, ‘u’ denotes an unsigned integer. ‘i’, jpayne@68: ‘d’, and ‘u’ may be preceded by a size specifier ‘l’. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:YCP sformat strings are described in the libycp documentation jpayne@68: file:/usr/share/doc/packages/libycp/YCP-builtins.html. jpayne@68: In summary, a directive starts with ‘%’ and is followed by ‘%’ jpayne@68: or a nonzero digit (‘1’ to ‘9’). jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68: jpayne@68:For the maintainer, the general procedure differs from the C language jpayne@68: case: jpayne@68:
jpayne@68:XGETTEXT_OPTIONS
jpayne@68: variable in ‘po/Makevars’ (see section ‘Makevars’ in ‘po/’) should be adjusted to
jpayne@68: match the xgettext
options for that particular programming language.
jpayne@68: If the package uses more than one programming language with gettext
jpayne@68: support, it becomes necessary to change the POT file construction rule
jpayne@68: in ‘po/Makefile.in.in’. It is recommended to make one xgettext
jpayne@68: invocation per programming language, each with the options appropriate for
jpayne@68: that language, and to combine the resulting files using msgcat
.
jpayne@68: gcc, gpp, gobjc, glibc, gettext jpayne@68:
jpayne@68:gcc, g++, gobjc, libc6-dev, libasprintf-dev jpayne@68:
jpayne@68:For C: c
, h
.
jpayne@68:
For C++: C
, c++
, cc
, cxx
, cpp
, hpp
.
jpayne@68:
For Objective C: m
.
jpayne@68:
"abc"
jpayne@68:
_("abc")
jpayne@68:
gettext
, dgettext
, dcgettext
, ngettext
,
jpayne@68: dngettext
, dcngettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
and wbindtextdomain
functions
jpayne@68:
Programmer must call setlocale (LC_ALL, "")
jpayne@68:
#include <libintl.h>
jpayne@68: #include <locale.h>
jpayne@68: #define _(string) gettext (string)
jpayne@68:
Use jpayne@68:
jpayne@68:xgettext -k_
jpayne@68:
fprintf "%2$d %1$d"
jpayne@68:
In C++: autosprintf "%2$d %1$d"
jpayne@68: (see (autosprintf)Top section `Introduction' in GNU autosprintf)
jpayne@68:
In C++ 20 or newer: std::vformat "{1} {0}"
jpayne@68:
autoconf (gettext.m4) and #if ENABLE_NLS jpayne@68:
jpayne@68:yes jpayne@68:
The following examples are available in the ‘examples’ directory:
jpayne@68: hello-c
, hello-c-gnome
, hello-c++
, hello-c++-qt
,
jpayne@68: hello-c++-kde
, hello-c++-gnome
, hello-c++-wxwidgets
,
jpayne@68: hello-objc
, hello-objc-gnustep
, hello-objc-gnome
.
jpayne@68:
python jpayne@68:
jpayne@68:python jpayne@68:
jpayne@68:py
jpayne@68:
'abc'
, u'abc'
, r'abc'
, ur'abc'
,
jpayne@68: "abc"
, u"abc"
, r"abc"
, ur"abc"
,
jpayne@68: '''abc'''
, u'''abc'''
, r'''abc'''
, ur'''abc'''
,
jpayne@68: """abc"""
, u"""abc"""
, r"""abc"""
, ur"""abc"""
jpayne@68:
_('abc')
etc.
jpayne@68:
gettext.gettext
, gettext.dgettext
,
jpayne@68: gettext.ngettext
, gettext.dngettext
,
jpayne@68: also ugettext
, ungettext
jpayne@68:
gettext.textdomain
function, or
jpayne@68: gettext.install(domain)
function
jpayne@68:
gettext.bindtextdomain
function, or
jpayne@68: gettext.install(domain,localedir)
function
jpayne@68:
not used by the gettext emulation jpayne@68:
jpayne@68:import gettext
jpayne@68:
emulate jpayne@68:
jpayne@68:xgettext
jpayne@68:
'...%(ident)d...' % { 'ident': value }
jpayne@68: '...{ident}...'.format(ident=value)
(see PEP 3101)
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-python
.
jpayne@68:
A note about format strings: Python supports format strings with unnamed
jpayne@68: arguments, such as '...%d...'
, and format strings with named arguments,
jpayne@68: such as '...%(ident)d...'
. The latter are preferable for
jpayne@68: internationalized programs, for two reasons:
jpayne@68:
"'%(volume)s' has only %(freespace)d bytes free." jpayne@68: |
to jpayne@68:
"Only %(freespace)d bytes free on '%(volume)s'." jpayne@68: |
Additionally, the identifiers also provide some context to the translator. jpayne@68:
jpayne@68:"one hour"
instead of "1 hour"
. Omitting
jpayne@68: individual arguments from format strings like this is only possible with
jpayne@68: the named argument syntax. (With unnamed arguments, Python – unlike C –
jpayne@68: verifies that the format string uses all supplied arguments.)
jpayne@68: java, java2 jpayne@68:
jpayne@68:default-jdk jpayne@68:
jpayne@68:java
jpayne@68:
"abc", """text block""" jpayne@68:
jpayne@68:i18n("abc") jpayne@68:
jpayne@68:GettextResource.gettext
, GettextResource.ngettext
,
jpayne@68: GettextResource.pgettext
, GettextResource.npgettext
jpayne@68:
—, use ResourceBundle.getResource
instead
jpayne@68:
—, use CLASSPATH instead jpayne@68:
jpayne@68:automatic jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:—, uses a Java specific message catalog format jpayne@68:
jpayne@68:xgettext -ki18n
jpayne@68:
MessageFormat.format "{1,number} {0,number}"
jpayne@68: or String.format "%2$d %1$d"
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
Before marking strings as internationalizable, uses of the string
jpayne@68: concatenation operator need to be converted to MessageFormat
jpayne@68: applications. For example, "file "+filename+" not found"
becomes
jpayne@68: MessageFormat.format("file {0} not found", new Object[] { filename })
.
jpayne@68: Only after this is done, can the strings be marked and extracted.
jpayne@68:
GNU gettext uses the native Java internationalization mechanism, namely
jpayne@68: ResourceBundle
s. There are two formats of ResourceBundle
s:
jpayne@68: .properties
files and .class
files. The .properties
jpayne@68: format is a text file which the translators can directly edit, like PO
jpayne@68: files, but which doesn't support plural forms. Whereas the .class
jpayne@68: format is compiled from .java
source code and can support plural
jpayne@68: forms (provided it is accessed through an appropriate API, see below).
jpayne@68:
To convert a PO file to a .properties
file, the msgcat
jpayne@68: program can be used with the option --properties-output
. To convert
jpayne@68: a .properties
file back to a PO file, the msgcat
program
jpayne@68: can be used with the option --properties-input
. All the tools
jpayne@68: that manipulate PO files can work with .properties
files as well,
jpayne@68: if given the --properties-input
and/or --properties-output
jpayne@68: option.
jpayne@68:
To convert a PO file to a ResourceBundle class, the msgfmt
program
jpayne@68: can be used with the option --java
or --java2
. To convert a
jpayne@68: ResourceBundle back to a PO file, the msgunfmt
program can be used
jpayne@68: with the option --java
.
jpayne@68:
Two different programmatic APIs can be used to access ResourceBundles.
jpayne@68: Note that both APIs work with all kinds of ResourceBundles, whether
jpayne@68: GNU gettext generated classes, or other .class
or .properties
jpayne@68: files.
jpayne@68:
java.util.ResourceBundle
API.
jpayne@68:
jpayne@68: In particular, its getString
function returns a string translation.
jpayne@68: Note that a missing translation yields a MissingResourceException
.
jpayne@68:
This has the advantage of being the standard API. And it does not require
jpayne@68: any additional libraries, only the msgcat
generated .properties
jpayne@68: files or the msgfmt
generated .class
files. But it cannot do
jpayne@68: plural handling, even if the resource was generated by msgfmt
from
jpayne@68: a PO file with plural handling.
jpayne@68:
gnu.gettext.GettextResource
API.
jpayne@68:
jpayne@68: Reference documentation in Javadoc 1.1 style format is in the jpayne@68: javadoc2 directory. jpayne@68:
jpayne@68:Its gettext
function returns a string translation. Note that when
jpayne@68: a translation is missing, the msgid argument is returned unchanged.
jpayne@68:
This has the advantage of having the ngettext
function for plural
jpayne@68: handling and the pgettext
and npgettext
for strings constraint
jpayne@68: to a particular context.
jpayne@68:
To use this API, one needs the libintl.jar
file which is part of
jpayne@68: the GNU gettext package and distributed under the LGPL.
jpayne@68:
Four examples, using the second API, are available in the ‘examples’
jpayne@68: directory: hello-java
, hello-java-awt
, hello-java-swing
,
jpayne@68: hello-java-qtjambi
.
jpayne@68:
Now, to make use of the API and define a shorthand for ‘getString’, jpayne@68: there are three idioms that you can choose from: jpayne@68:
jpayne@68:ResourceBundle
instance and the shorthand:
jpayne@68:
jpayne@68: private static ResourceBundle myResources = jpayne@68: ResourceBundle.getBundle("domain-name"); jpayne@68: public static String i18n(String s) { jpayne@68: return myResources.getString(s); jpayne@68: } jpayne@68: |
All classes containing internationalized strings then contain jpayne@68:
jpayne@68:import static Util.i18n; jpayne@68: |
and the shorthand is used like this: jpayne@68:
jpayne@68:System.out.println(i18n("Operation completed.")); jpayne@68: |
ResourceBundle
instance:
jpayne@68:
jpayne@68: public static ResourceBundle myResources = jpayne@68: ResourceBundle.getBundle("domain-name"); jpayne@68: |
All classes containing internationalized strings then contain jpayne@68:
jpayne@68:private static ResourceBundle res = Util.myResources; jpayne@68: private static String i18n(String s) { return res.getString(s); } jpayne@68: |
and the shorthand is used like this: jpayne@68:
jpayne@68:System.out.println(i18n("Operation completed.")); jpayne@68: |
public class S { jpayne@68: public static ResourceBundle myResources = jpayne@68: ResourceBundle.getBundle("domain-name"); jpayne@68: public static String i18n(String s) { jpayne@68: return myResources.getString(s); jpayne@68: } jpayne@68: } jpayne@68: |
and the shorthand is used like this: jpayne@68:
jpayne@68:System.out.println(S.i18n("Operation completed.")); jpayne@68: |
Which of the three idioms you choose, will depend on whether your project jpayne@68: requires portability to Java versions prior to Java 1.5 and, if so, whether jpayne@68: copying two lines of codes into every class is more acceptable in your project jpayne@68: than a class with a single-letter name. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:mono jpayne@68:
jpayne@68:mono-mcs jpayne@68:
jpayne@68:cs
jpayne@68:
"abc"
, @"abc"
jpayne@68:
_("abc") jpayne@68:
jpayne@68:GettextResourceManager.GetString
,
jpayne@68: GettextResourceManager.GetPluralString
jpayne@68: GettextResourceManager.GetParticularString
jpayne@68: GettextResourceManager.GetParticularPluralString
jpayne@68:
new GettextResourceManager(domain)
jpayne@68:
—, compiled message catalogs are located in subdirectories of the directory jpayne@68: containing the executable jpayne@68:
jpayne@68:automatic jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:—, uses a C# specific message catalog format jpayne@68:
jpayne@68:xgettext -k_
jpayne@68:
String.Format "{1} {0}"
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
Before marking strings as internationalizable, uses of the string
jpayne@68: concatenation operator need to be converted to String.Format
jpayne@68: invocations. For example, "file "+filename+" not found"
becomes
jpayne@68: String.Format("file {0} not found", filename)
.
jpayne@68: Only after this is done, can the strings be marked and extracted.
jpayne@68:
GNU gettext uses the native C#/.NET internationalization mechanism, namely
jpayne@68: the classes ResourceManager
and ResourceSet
. Applications
jpayne@68: use the ResourceManager
methods to retrieve the native language
jpayne@68: translation of strings. An instance of ResourceSet
is the in-memory
jpayne@68: representation of a message catalog file. The ResourceManager
loads
jpayne@68: and accesses ResourceSet
instances as needed to look up the
jpayne@68: translations.
jpayne@68:
There are two formats of ResourceSet
s that can be directly loaded by
jpayne@68: the C# runtime: .resources
files and .dll
files.
jpayne@68:
.resources
format is a binary file usually generated through the
jpayne@68: resgen
or monoresgen
utility, but which doesn't support plural
jpayne@68: forms. .resources
files can also be embedded in .NET .exe
files.
jpayne@68: This only affects whether a file system access is performed to load the message
jpayne@68: catalog; it doesn't affect the contents of the message catalog.
jpayne@68:
jpayne@68: .dll
format is a binary file that is compiled
jpayne@68: from .cs
source code and can support plural forms (provided it is
jpayne@68: accessed through the GNU gettext API, see below).
jpayne@68: Note that these .NET .dll
and .exe
files are not tied to a
jpayne@68: particular platform; their file format and GNU gettext for C# can be used
jpayne@68: on any platform.
jpayne@68:
To convert a PO file to a .resources
file, the msgfmt
program
jpayne@68: can be used with the option ‘--csharp-resources’. To convert a
jpayne@68: .resources
file back to a PO file, the msgunfmt
program can be
jpayne@68: used with the option ‘--csharp-resources’. You can also, in some cases,
jpayne@68: use the monoresgen
program (from the mono
/mcs
package).
jpayne@68: This program can also convert a .resources
file back to a PO file. But
jpayne@68: beware: as of this writing (January 2004), the monoresgen
converter is
jpayne@68: quite buggy.
jpayne@68:
To convert a PO file to a .dll
file, the msgfmt
program can be
jpayne@68: used with the option --csharp
. The result will be a .dll
file
jpayne@68: containing a subclass of GettextResourceSet
, which itself is a subclass
jpayne@68: of ResourceSet
. To convert a .dll
file containing a
jpayne@68: GettextResourceSet
subclass back to a PO file, the msgunfmt
jpayne@68: program can be used with the option --csharp
.
jpayne@68:
The advantages of the .dll
format over the .resources
format
jpayne@68: are:
jpayne@68:
ResourceManager
constructor provided by the system, the set of
jpayne@68: .resources
files for an application must be specified when the
jpayne@68: application is built and cannot be extended afterwards.
jpayne@68:
jpayne@68: .dll
format supports the plural
jpayne@68: handling function GetPluralString
. Whereas .resources
files can
jpayne@68: only contain data and only support lookups that depend on a single string.
jpayne@68:
jpayne@68: .dll
format supports the
jpayne@68: query-with-context functions GetParticularString
and
jpayne@68: GetParticularPluralString
. Whereas .resources
files can
jpayne@68: only contain data and only support lookups that depend on a single string.
jpayne@68:
jpayne@68: GettextResourceManager
that loads the message catalogs in
jpayne@68: .dll
format also provides for inheritance on a per-message basis.
jpayne@68: For example, in Austrian (de_AT
) locale, translations from the German
jpayne@68: (de
) message catalog will be used for messages not found in the
jpayne@68: Austrian message catalog. This has the consequence that the Austrian
jpayne@68: translators need only translate those few messages for which the translation
jpayne@68: into Austrian differs from the German one. Whereas when working with
jpayne@68: .resources
files, each message catalog must provide the translations
jpayne@68: of all messages by itself.
jpayne@68:
jpayne@68: GettextResourceManager
that loads the message catalogs in
jpayne@68: .dll
format also provides for a fallback: The English msgid is
jpayne@68: returned when no translation can be found. Whereas when working with
jpayne@68: .resources
files, a language-neutral .resources
file must
jpayne@68: explicitly be provided as a fallback.
jpayne@68: On the side of the programmatic APIs, the programmer can use either the
jpayne@68: standard ResourceManager
API and the GNU GettextResourceManager
jpayne@68: API. The latter is an extension of the former, because
jpayne@68: GettextResourceManager
is a subclass of ResourceManager
.
jpayne@68:
System.Resources.ResourceManager
API.
jpayne@68:
jpayne@68: This API works with resources in .resources
format.
jpayne@68:
The creation of the ResourceManager
is done through
jpayne@68:
new ResourceManager(domainname, Assembly.GetExecutingAssembly()) jpayne@68: |
The GetString
function returns a string's translation. Note that this
jpayne@68: function returns null when a translation is missing (i.e. not even found in
jpayne@68: the fallback resource file).
jpayne@68:
GNU.Gettext.GettextResourceManager
API.
jpayne@68:
jpayne@68: This API works with resources in .dll
format.
jpayne@68:
Reference documentation is in the jpayne@68: csharpdoc directory. jpayne@68:
jpayne@68:The creation of the ResourceManager
is done through
jpayne@68:
new GettextResourceManager(domainname) jpayne@68: |
The GetString
function returns a string's translation. Note that when
jpayne@68: a translation is missing, the msgid argument is returned unchanged.
jpayne@68:
The GetPluralString
function returns a string translation with plural
jpayne@68: handling, like the ngettext
function in C.
jpayne@68:
The GetParticularString
function returns a string's translation,
jpayne@68: specific to a particular context, like the pgettext
function in C.
jpayne@68: Note that when a translation is missing, the msgid argument is returned
jpayne@68: unchanged.
jpayne@68:
The GetParticularPluralString
function returns a string translation,
jpayne@68: specific to a particular context, with plural handling, like the
jpayne@68: npgettext
function in C.
jpayne@68:
To use this API, one needs the GNU.Gettext.dll
file which is part of
jpayne@68: the GNU gettext package and distributed under the LGPL.
jpayne@68:
You can also mix both approaches: use the
jpayne@68: GNU.Gettext.GettextResourceManager
constructor, but otherwise use
jpayne@68: only the ResourceManager
type and only the GetString
method.
jpayne@68: This is appropriate when you want to profit from the tools for PO files,
jpayne@68: but don't want to change an existing source code that uses
jpayne@68: ResourceManager
and don't (yet) need the GetPluralString
method.
jpayne@68:
Two examples, using the second API, are available in the ‘examples’
jpayne@68: directory: hello-csharp
, hello-csharp-forms
.
jpayne@68:
Now, to make use of the API and define a shorthand for ‘GetString’, jpayne@68: there are two idioms that you can choose from: jpayne@68:
jpayne@68:ResourceManager
instance:
jpayne@68:
jpayne@68: public static GettextResourceManager MyResourceManager = jpayne@68: new GettextResourceManager("domain-name"); jpayne@68: |
All classes containing internationalized strings then contain jpayne@68:
jpayne@68:private static GettextResourceManager Res = Util.MyResourceManager; jpayne@68: private static String _(String s) { return Res.GetString(s); } jpayne@68: |
and the shorthand is used like this: jpayne@68:
jpayne@68:Console.WriteLine(_("Operation completed.")); jpayne@68: |
public class S { jpayne@68: public static GettextResourceManager MyResourceManager = jpayne@68: new GettextResourceManager("domain-name"); jpayne@68: public static String _(String s) { jpayne@68: return MyResourceManager.GetString(s); jpayne@68: } jpayne@68: } jpayne@68: |
and the shorthand is used like this: jpayne@68:
jpayne@68:Console.WriteLine(S._("Operation completed.")); jpayne@68: |
Which of the two idioms you choose, will depend on whether copying two lines jpayne@68: of codes into every class is more acceptable in your project than a class jpayne@68: with a single-letter name. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:js jpayne@68:
jpayne@68:gjs jpayne@68:
jpayne@68:js
jpayne@68:
"abc"
jpayne@68:
jpayne@68: 'abc'
jpayne@68:
jpayne@68: `abc`
jpayne@68:
jpayne@68: _("abc")
jpayne@68:
gettext
, dgettext
, dcgettext
, ngettext
,
jpayne@68: dngettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
automatic jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:use, or emulate jpayne@68:
jpayne@68:xgettext
jpayne@68:
— jpayne@68:
jpayne@68:On platforms without gettext, the functions are not available. jpayne@68:
jpayne@68:— jpayne@68:
guile jpayne@68:
jpayne@68:guile-2.0 jpayne@68:
jpayne@68:scm
jpayne@68:
"abc"
jpayne@68:
(_ "abc")
, _"abc"
(GIMP script-fu extension)
jpayne@68:
gettext
, ngettext
jpayne@68:
textdomain
jpayne@68:
bindtextdomain
jpayne@68:
(catch #t (lambda () (setlocale LC_ALL "")) (lambda args #f))
jpayne@68:
(use-modules (ice-9 format))
jpayne@68:
use jpayne@68:
jpayne@68:xgettext -k_
jpayne@68:
— jpayne@68:
jpayne@68:On platforms without gettext, no translation. jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-guile
.
jpayne@68:
clisp 2.28 or newer jpayne@68:
jpayne@68:clisp jpayne@68:
jpayne@68:lisp
jpayne@68:
"abc"
jpayne@68:
(_ "abc")
, (ENGLISH "abc")
jpayne@68:
i18n:gettext
, i18n:ngettext
jpayne@68:
i18n:textdomain
jpayne@68:
i18n:textdomaindir
jpayne@68:
automatic jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:use jpayne@68:
jpayne@68:xgettext -k_ -kENGLISH
jpayne@68:
format "~1@*~D ~0@*~D"
jpayne@68:
On platforms without gettext, no translation. jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-clisp
.
jpayne@68:
clisp jpayne@68:
jpayne@68:clisp jpayne@68:
jpayne@68:d
jpayne@68:
"abc"
jpayne@68:
ENGLISH ? "abc" : ""
jpayne@68: GETTEXT("abc")
jpayne@68: GETTEXTL("abc")
jpayne@68:
clgettext
, clgettextl
jpayne@68:
— jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:automatic jpayne@68:
jpayne@68:#include "lispbibl.c"
jpayne@68:
use jpayne@68:
jpayne@68:clisp-xgettext
jpayne@68:
fprintf "%2$d %1$d"
jpayne@68:
On platforms without gettext, no translation. jpayne@68:
jpayne@68:— jpayne@68:
emacs, xemacs jpayne@68:
jpayne@68:emacs, xemacs21 jpayne@68:
jpayne@68:el
jpayne@68:
"abc"
jpayne@68:
(_"abc")
jpayne@68:
gettext
, dgettext
(xemacs only)
jpayne@68:
domain
special form (xemacs only)
jpayne@68:
bind-text-domain
function (xemacs only)
jpayne@68:
automatic jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:use jpayne@68:
jpayne@68:xgettext
jpayne@68:
format "%2$d %1$d"
jpayne@68:
Only XEmacs. Without I18N3
defined at build time, no translation.
jpayne@68:
— jpayne@68:
librep 0.15.3 or newer jpayne@68:
jpayne@68:librep16 jpayne@68:
jpayne@68:jl
jpayne@68:
"abc"
jpayne@68:
(_"abc")
jpayne@68:
gettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
— jpayne@68:
jpayne@68:(require 'rep.i18n.gettext)
jpayne@68:
use jpayne@68:
jpayne@68:xgettext
jpayne@68:
format "%2$d %1$d"
jpayne@68:
On platforms without gettext, no translation. jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-librep
.
jpayne@68:
ruby, ruby-gettext jpayne@68:
jpayne@68:ruby, ruby-gettext jpayne@68:
jpayne@68:rb
jpayne@68:
"abc"
, 'abc'
, %q/abc/
etc.,
jpayne@68: %q(abc)
, %q[abc]
, %q{abc}
jpayne@68:
_("abc")
jpayne@68:
gettext
, ngettext
jpayne@68:
— jpayne@68:
jpayne@68:bindtextdomain
function
jpayne@68:
— jpayne@68:
jpayne@68:require 'gettext'
jpayne@68: include GetText
jpayne@68:
emulate jpayne@68:
jpayne@68:xgettext
jpayne@68:
sprintf("%2$d %1$d", x, y)
jpayne@68: "%{new} replaces %{old}" % {:old => oldvalue, :new => newvalue}
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
bash, gettext jpayne@68:
jpayne@68:bash, gettext-base jpayne@68:
jpayne@68:sh
jpayne@68:
"abc"
, 'abc'
, abc
jpayne@68:
"`gettext \"abc\"`"
jpayne@68:
gettext
, ngettext
programs
jpayne@68: eval_gettext
, eval_ngettext
, eval_pgettext
,
jpayne@68: eval_npgettext
shell functions
jpayne@68:
environment variable TEXTDOMAIN
jpayne@68:
environment variable TEXTDOMAINDIR
jpayne@68:
automatic jpayne@68:
jpayne@68:. gettext.sh
jpayne@68:
use jpayne@68:
jpayne@68:xgettext
jpayne@68:
— jpayne@68:
jpayne@68:fully portable jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-sh
.
jpayne@68:
Preparing a shell script for internationalization is conceptually similar jpayne@68: to the steps described in Preparing Program Sources. The concrete steps for shell jpayne@68: scripts are as follows. jpayne@68:
jpayne@68:. gettext.sh jpayne@68: |
near the top of the script. gettext.sh
is a shell function library
jpayne@68: that provides the functions
jpayne@68: eval_gettext
(see Invoking the eval_gettext
function),
jpayne@68: eval_ngettext
(see Invoking the eval_ngettext
function),
jpayne@68: eval_pgettext
(see Invoking the eval_pgettext
function), and
jpayne@68: eval_npgettext
(see Invoking the eval_npgettext
function).
jpayne@68: You have to ensure that gettext.sh
can be found in the PATH
.
jpayne@68:
TEXTDOMAIN
and TEXTDOMAINDIR
environment
jpayne@68: variables. Usually TEXTDOMAIN
is the package or program name, and
jpayne@68: TEXTDOMAINDIR
is the absolute pathname corresponding to
jpayne@68: $prefix/share/locale
, where $prefix
is the installation location.
jpayne@68:
jpayne@68: TEXTDOMAIN=@PACKAGE@ jpayne@68: export TEXTDOMAIN jpayne@68: TEXTDOMAINDIR=@LOCALEDIR@ jpayne@68: export TEXTDOMAINDIR jpayne@68: |
"`...`"
or "$(...)"
), variable access with defaulting (like
jpayne@68: ${variable-default}
), access to positional arguments
jpayne@68: (like $0
, $1
, ...) or highly volatile shell variables (like
jpayne@68: $?
). This can always be done through simple local code restructuring.
jpayne@68: For example,
jpayne@68:
jpayne@68: echo "Usage: $0 [OPTION] FILE..." jpayne@68: |
becomes jpayne@68:
jpayne@68:program_name=$0 jpayne@68: echo "Usage: $program_name [OPTION] FILE..." jpayne@68: |
Similarly, jpayne@68:
jpayne@68:echo "Remaining files: `ls | wc -l`" jpayne@68: |
becomes jpayne@68:
jpayne@68:filecount="`ls | wc -l`" jpayne@68: echo "Remaining files: $filecount" jpayne@68: |
When doing this, you also need to add an extra backslash before the dollar jpayne@68: sign in references to shell variables, so that the ‘eval_gettext’ jpayne@68: function receives the translatable string before the variable values are jpayne@68: substituted into it. For example, jpayne@68:
jpayne@68:echo "Remaining files: $filecount" jpayne@68: |
becomes jpayne@68:
jpayne@68:eval_gettext "Remaining files: \$filecount"; echo jpayne@68: |
If the output command is not ‘echo’, you can make it use ‘echo’ jpayne@68: nevertheless, through the use of backquotes. However, note that inside jpayne@68: backquotes, backslashes must be doubled to be effective (because the jpayne@68: backquoting eats one level of backslashes). For example, assuming that jpayne@68: ‘error’ is a shell function that signals an error, jpayne@68:
jpayne@68:error "file not found: $filename" jpayne@68: |
is first transformed into jpayne@68:
jpayne@68:error "`echo \"file not found: \$filename\"`" jpayne@68: |
which then becomes jpayne@68:
jpayne@68:error "`eval_gettext \"file not found: \\\$filename\"`" jpayne@68: |
gettext.sh
gettext.sh
, contained in the run-time package of GNU gettext, provides
jpayne@68: the following:
jpayne@68:
echo
is set to a command that outputs its first argument
jpayne@68: and a newline, without interpreting backslashes in the argument string.
jpayne@68:
jpayne@68: eval_gettext
function.
jpayne@68:
jpayne@68: eval_ngettext
function.
jpayne@68:
jpayne@68: eval_pgettext
function.
jpayne@68:
jpayne@68: eval_npgettext
function.
jpayne@68: gettext
program gettext [option] [[textdomain] msgid] jpayne@68: gettext [option] -s [msgid]... jpayne@68: |
The gettext
program displays the native language translation of a
jpayne@68: textual message.
jpayne@68:
Arguments jpayne@68:
jpayne@68:Specify the context for the messages to be translated. jpayne@68: See Using contexts for solving ambiguities for details. jpayne@68:
jpayne@68:Retrieve translated messages from textdomain. Usually a textdomain jpayne@68: corresponds to a package, a program, or a module of a program. jpayne@68:
jpayne@68:Enable expansion of some escape sequences. This option is for compatibility jpayne@68: with the ‘echo’ program or shell built-in. The escape sequences jpayne@68: ‘\a’, ‘\b’, ‘\c’, ‘\f’, ‘\n’, ‘\r’, ‘\t’, jpayne@68: ‘\v’, ‘\\’, and ‘\’ followed by one to three octal digits, are jpayne@68: interpreted like the System V ‘echo’ program did. jpayne@68:
jpayne@68:This option is only for compatibility with the ‘echo’ program or shell jpayne@68: built-in. It has no effect. jpayne@68:
jpayne@68:Display this help and exit. jpayne@68:
jpayne@68:This option has only an effect if the -s
option is given. It
jpayne@68: suppresses the additional newline at the end.
jpayne@68:
Output version information and exit. jpayne@68:
jpayne@68:Retrieve translated message corresponding to msgid from textdomain. jpayne@68:
jpayne@68:If the textdomain parameter is not given, the domain is determined from
jpayne@68: the environment variable TEXTDOMAIN
. If the message catalog is not
jpayne@68: found in the regular directory, another location can be specified with the
jpayne@68: environment variable TEXTDOMAINDIR
.
jpayne@68:
When used with the -s
option the program behaves like the ‘echo’
jpayne@68: command. But it does not simply copy its arguments to stdout. Instead those
jpayne@68: messages found in the selected catalog are translated. Also, a newline is
jpayne@68: added at the end, unless either the option -n
is specified or the
jpayne@68: option -e
is specified and some of the argument strings contains a
jpayne@68: ‘\c’ escape sequence.
jpayne@68:
Note: xgettext
supports only the one-argument form of the
jpayne@68: gettext
invocation, where no options are present and the
jpayne@68: textdomain is implicit, from the environment.
jpayne@68:
ngettext
program ngettext [option] [textdomain] msgid msgid-plural count jpayne@68: |
The ngettext
program displays the native language translation of a
jpayne@68: textual message whose grammatical form depends on a number.
jpayne@68:
Arguments jpayne@68:
jpayne@68:Specify the context for the messages to be translated. jpayne@68: See Using contexts for solving ambiguities for details. jpayne@68:
jpayne@68:Retrieve translated messages from textdomain. Usually a textdomain jpayne@68: corresponds to a package, a program, or a module of a program. jpayne@68:
jpayne@68:Enable expansion of some escape sequences. This option is for compatibility jpayne@68: with the ‘gettext’ program. The escape sequences jpayne@68: ‘\a’, ‘\b’, ‘\f’, ‘\n’, ‘\r’, ‘\t’, jpayne@68: ‘\v’, ‘\\’, and ‘\’ followed by one to three octal digits, are jpayne@68: interpreted like the System V ‘echo’ program did. jpayne@68:
jpayne@68:This option is only for compatibility with the ‘gettext’ program. It has jpayne@68: no effect. jpayne@68:
jpayne@68:Display this help and exit. jpayne@68:
jpayne@68:Output version information and exit. jpayne@68:
jpayne@68:Retrieve translated message from textdomain. jpayne@68:
jpayne@68:Translate msgid (English singular) / msgid-plural (English plural). jpayne@68:
jpayne@68:Choose singular/plural form based on this value. jpayne@68:
jpayne@68:If the textdomain parameter is not given, the domain is determined from
jpayne@68: the environment variable TEXTDOMAIN
. If the message catalog is not
jpayne@68: found in the regular directory, another location can be specified with the
jpayne@68: environment variable TEXTDOMAINDIR
.
jpayne@68:
Note: xgettext
supports only the three-arguments form of the
jpayne@68: ngettext
invocation, where no options are present and the
jpayne@68: textdomain is implicit, from the environment.
jpayne@68:
envsubst
program envsubst [option] [shell-format] jpayne@68: |
The envsubst
program substitutes the values of environment variables.
jpayne@68:
Operation mode jpayne@68:
jpayne@68:Output the variables occurring in shell-format. jpayne@68:
jpayne@68:Informative output jpayne@68:
jpayne@68:Display this help and exit. jpayne@68:
jpayne@68:Output version information and exit. jpayne@68:
jpayne@68:In normal operation mode, standard input is copied to standard output,
jpayne@68: with references to environment variables of the form $VARIABLE
or
jpayne@68: ${VARIABLE}
being replaced with the corresponding values. If a
jpayne@68: shell-format is given, only those environment variables that are
jpayne@68: referenced in shell-format are substituted; otherwise all environment
jpayne@68: variables references occurring in standard input are substituted.
jpayne@68:
These substitutions are a subset of the substitutions that a shell performs
jpayne@68: on unquoted and double-quoted strings. Other kinds of substitutions done
jpayne@68: by a shell, such as ${variable-default}
or
jpayne@68: $(command-list)
or `command-list`
, are not performed
jpayne@68: by the envsubst
program, due to security reasons.
jpayne@68:
When --variables
is used, standard input is ignored, and the output
jpayne@68: consists of the environment variables that are referenced in
jpayne@68: shell-format, one per line.
jpayne@68:
eval_gettext
function eval_gettext msgid jpayne@68: |
This function outputs the native language translation of a textual message, jpayne@68: performing dollar-substitution on the result. Note that only shell variables jpayne@68: mentioned in msgid will be dollar-substituted in the result. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:eval_ngettext
function eval_ngettext msgid msgid-plural count jpayne@68: |
This function outputs the native language translation of a textual message jpayne@68: whose grammatical form depends on a number, performing dollar-substitution jpayne@68: on the result. Note that only shell variables mentioned in msgid or jpayne@68: msgid-plural will be dollar-substituted in the result. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:eval_pgettext
function eval_pgettext msgctxt msgid jpayne@68: |
This function outputs the native language translation of a textual message jpayne@68: in the given context msgctxt (see Using contexts for solving ambiguities), performing jpayne@68: dollar-substitution on the result. Note that only shell variables mentioned jpayne@68: in msgid will be dollar-substituted in the result. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:eval_npgettext
function eval_npgettext msgctxt msgid msgid-plural count jpayne@68: |
This function outputs the native language translation of a textual message jpayne@68: whose grammatical form depends on a number in the given context msgctxt jpayne@68: (see Using contexts for solving ambiguities), performing dollar-substitution on the result. Note jpayne@68: that only shell variables mentioned in msgid or msgid-plural jpayne@68: will be dollar-substituted in the result. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:GNU bash
2.0 or newer has a special shorthand for translating a
jpayne@68: string and substituting variable values in it: $"msgid"
. But
jpayne@68: the use of this construct is discouraged, due to the security
jpayne@68: holes it opens and due to its portability problems.
jpayne@68:
The security holes of $"..."
come from the fact that after looking up
jpayne@68: the translation of the string, bash
processes it like it processes
jpayne@68: any double-quoted string: dollar and backquote processing, like ‘eval’
jpayne@68: does.
jpayne@68:
0x60
. For example, the byte sequence \xe0\x60
is a single
jpayne@68: character in these locales. Many versions of bash
(all versions
jpayne@68: up to bash-2.05, and newer versions on platforms without mbsrtowcs()
jpayne@68: function) don't know about character boundaries and see a backquote character
jpayne@68: where there is only a particular Chinese character. Thus it can start
jpayne@68: executing part of the translation as a command list. This situation can occur
jpayne@68: even without the translator being aware of it: if the translator provides
jpayne@68: translations in the UTF-8 encoding, it is the gettext()
function which
jpayne@68: will, during its conversion from the translator's encoding to the user's
jpayne@68: locale's encoding, produce the dangerous \x60
bytes.
jpayne@68:
jpayne@68: "`...`"
or dollar-parentheses "$(...)"
in her translations.
jpayne@68: The enclosed strings would be executed as command lists by the shell.
jpayne@68: The portability problem is that bash
must be built with
jpayne@68: internationalization support; this is normally not the case on systems
jpayne@68: that don't have the gettext()
function in libc.
jpayne@68:
gawk 3.1 or newer jpayne@68:
jpayne@68:gawk jpayne@68:
jpayne@68:awk
, gawk
, twjr
.
jpayne@68: The file extension twjr
is used by TexiWeb Jr
jpayne@68: (https://github.com/arnoldrobbins/texiwebjr).
jpayne@68:
"abc"
jpayne@68:
_"abc"
jpayne@68:
dcgettext
, missing dcngettext
in gawk-3.1.0
jpayne@68:
TEXTDOMAIN
variable
jpayne@68:
bindtextdomain
function
jpayne@68:
automatic, but missing setlocale (LC_MESSAGES, "")
in gawk-3.1.0
jpayne@68:
— jpayne@68:
jpayne@68:use jpayne@68:
jpayne@68:xgettext
jpayne@68:
printf "%2$d %1$d"
(GNU awk only)
jpayne@68:
On platforms without gettext, no translation. On non-GNU awks, you must
jpayne@68: define dcgettext
, dcngettext
and bindtextdomain
jpayne@68: yourself.
jpayne@68:
— jpayne@68:
An example is available in the ‘examples’ directory: hello-gawk
.
jpayne@68:
lua jpayne@68:
jpayne@68:lua, lua-gettext
jpayne@68:
jpayne@68: You need to install the lua-gettext
package from
jpayne@68: https://gitlab.com/sukhichev/lua-gettext/blob/master/README.us.md.
jpayne@68: Debian and Ubuntu packages of it are available. Download the
jpayne@68: appropriate one, and install it through
jpayne@68: ‘sudo dpkg -i lua-gettext_0.0_amd64.deb’.
jpayne@68:
lua
jpayne@68:
"abc"
jpayne@68:
jpayne@68: 'abc'
jpayne@68:
jpayne@68: [[abc]]
jpayne@68:
jpayne@68: [=[abc]=]
jpayne@68:
jpayne@68: [==[abc]==]
jpayne@68:
jpayne@68: _("abc")
jpayne@68:
gettext.gettext
, gettext.dgettext
, gettext.dcgettext
,
jpayne@68: gettext.ngettext
, gettext.dngettext
, gettext.dcngettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
automatic jpayne@68:
jpayne@68:require 'gettext'
or running lua interpreter with -l gettext
option
jpayne@68:
use jpayne@68:
jpayne@68:xgettext
jpayne@68:
— jpayne@68:
jpayne@68:On platforms without gettext, the functions are not available. jpayne@68:
jpayne@68:— jpayne@68:
fpk jpayne@68:
jpayne@68:fp-compiler, fp-units-fcl jpayne@68:
jpayne@68:pp
, pas
jpayne@68:
'abc'
jpayne@68:
automatic jpayne@68:
jpayne@68:—, use ResourceString
data type instead
jpayne@68:
—, use TranslateResourceStrings
function instead
jpayne@68:
—, use TranslateResourceStrings
function instead
jpayne@68:
automatic, but uses only LANG, not LC_MESSAGES or LC_ALL jpayne@68:
jpayne@68:{$mode delphi}
or {$mode objfpc}
uses gettext;
jpayne@68:
emulate partially jpayne@68:
jpayne@68:ppc386
followed by xgettext
or rstconv
jpayne@68:
uses sysutils;
format "%1:d %0:d"
jpayne@68:
? jpayne@68:
jpayne@68:— jpayne@68:
The Pascal compiler has special support for the ResourceString
data
jpayne@68: type. It generates a .rst
file. This is then converted to a
jpayne@68: .pot
file by use of xgettext
or rstconv
. At runtime,
jpayne@68: a .mo
file corresponding to translations of this .pot
file
jpayne@68: can be loaded using the TranslateResourceStrings
function in the
jpayne@68: gettext
unit.
jpayne@68:
An example is available in the ‘examples’ directory: hello-pascal
.
jpayne@68:
smalltalk jpayne@68:
jpayne@68:gnu-smalltalk jpayne@68:
jpayne@68:st
jpayne@68:
'abc'
jpayne@68:
NLS ? 'abc'
jpayne@68:
LcMessagesDomain>>#at:
, LcMessagesDomain>>#at:plural:with:
jpayne@68:
LcMessages>>#domain:localeDirectory:
(returns a LcMessagesDomain
jpayne@68: object).
jpayne@68: Example: I18N Locale default messages domain: 'gettext' localeDirectory: /usr/local/share/locale'
jpayne@68:
LcMessages>>#domain:localeDirectory:
, see above.
jpayne@68:
Automatic if you use I18N Locale default
.
jpayne@68:
PackageLoader fileInPackage: 'I18N'!
jpayne@68:
emulate jpayne@68:
jpayne@68:xgettext
jpayne@68:
'%1 %2' bindWith: 'Hello' with: 'world'
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory:
jpayne@68: hello-smalltalk
.
jpayne@68:
vala jpayne@68:
jpayne@68:valac jpayne@68:
jpayne@68:vala
jpayne@68:
"abc"
jpayne@68:
jpayne@68: """abc"""
jpayne@68:
jpayne@68: _("abc")
jpayne@68:
gettext
, dgettext
, dcgettext
, ngettext
,
jpayne@68: dngettext
, dpgettext
, dpgettext2
jpayne@68:
textdomain
function, defined under the Intl
namespace
jpayne@68:
bindtextdomain
function, defined under the Intl
namespace
jpayne@68:
Programmer must call Intl.setlocale (LocaleCategory.ALL, "")
jpayne@68:
— jpayne@68:
jpayne@68:Use jpayne@68:
jpayne@68:xgettext
jpayne@68:
Same as for the C language. jpayne@68:
jpayne@68:autoconf (gettext.m4) and #if ENABLE_NLS jpayne@68:
jpayne@68:yes jpayne@68:
wxGTK, gettext jpayne@68:
jpayne@68:libwxgtk3.0-dev jpayne@68:
jpayne@68:cpp
jpayne@68:
"abc"
jpayne@68:
_("abc")
jpayne@68:
wxLocale::GetString
, wxGetTranslation
jpayne@68:
wxLocale::AddCatalog
jpayne@68:
wxLocale::AddCatalogLookupPathPrefix
jpayne@68:
wxLocale::Init
, wxSetLocale
jpayne@68:
#include <wx/intl.h>
jpayne@68:
emulate, see include/wx/intl.h
and src/common/intl.cpp
jpayne@68:
xgettext
jpayne@68:
wxString::Format supports positions if and only if the system has
jpayne@68: wprintf()
, vswprintf()
functions and they support positions
jpayne@68: according to POSIX.
jpayne@68:
fully portable jpayne@68:
jpayne@68:yes jpayne@68:
tcl jpayne@68:
jpayne@68:tcl jpayne@68:
jpayne@68:tcl
jpayne@68:
"abc"
jpayne@68:
[_ "abc"]
jpayne@68:
::msgcat::mc
jpayne@68:
— jpayne@68:
jpayne@68:—, use ::msgcat::mcload
instead
jpayne@68:
automatic, uses LANG, but ignores LC_MESSAGES and LC_ALL jpayne@68:
jpayne@68:package require msgcat
jpayne@68: proc _ {s} {return [::msgcat::mc $s]}
jpayne@68:
—, uses a Tcl specific message catalog format jpayne@68:
jpayne@68:xgettext -k_
jpayne@68:
format "%2\$d %1\$d"
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
Two examples are available in the ‘examples’ directory:
jpayne@68: hello-tcl
, hello-tcl-tk
.
jpayne@68:
Before marking strings as internationalizable, substitutions of variables
jpayne@68: into the string need to be converted to format
applications. For
jpayne@68: example, "file $filename not found"
becomes
jpayne@68: [format "file %s not found" $filename]
.
jpayne@68: Only after this is done, can the strings be marked and extracted.
jpayne@68: After marking, this example becomes
jpayne@68: [format [_ "file %s not found"] $filename]
or
jpayne@68: [msgcat::mc "file %s not found" $filename]
. Note that the
jpayne@68: msgcat::mc
function implicitly calls format
when more than one
jpayne@68: argument is given.
jpayne@68:
perl jpayne@68:
jpayne@68:perl, libintl-perl jpayne@68:
jpayne@68:pl
, PL
, pm
, perl
, cgi
jpayne@68:
"abc"
jpayne@68:
jpayne@68: 'abc'
jpayne@68:
jpayne@68: qq (abc)
jpayne@68:
jpayne@68: q (abc)
jpayne@68:
jpayne@68: qr /abc/
jpayne@68:
jpayne@68: qx (/bin/date)
jpayne@68:
jpayne@68: /pattern match/
jpayne@68:
jpayne@68: ?pattern match?
jpayne@68:
jpayne@68: s/substitution/operators/
jpayne@68:
jpayne@68: $tied_hash{"message"}
jpayne@68:
jpayne@68: $tied_hash_reference->{"message"}
jpayne@68:
jpayne@68: __
(double underscore)
jpayne@68:
gettext
, dgettext
, dcgettext
, ngettext
,
jpayne@68: dngettext
, dcngettext
, pgettext
, dpgettext
,
jpayne@68: dcpgettext
, npgettext
, dnpgettext
,
jpayne@68: dcnpgettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
bind_textdomain_codeset
function
jpayne@68:
Use setlocale (LC_ALL, "");
jpayne@68:
use POSIX;
jpayne@68: use Locale::TextDomain;
(included in the package libintl-perl
jpayne@68: which is available on the Comprehensive Perl Archive Network CPAN,
jpayne@68: https://www.cpan.org/).
jpayne@68:
platform dependent: gettext_pp emulates, gettext_xs uses GNU gettext jpayne@68:
jpayne@68:xgettext -k__ -k\$__ -k%__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2
jpayne@68: -kN__ -kN__n:1,2 -k__p:1c,2 -k__np:1c,2,3 -kN__p:1c,2 -kN__np:1c,2,3
jpayne@68:
Both kinds of format strings support formatting with positions.
jpayne@68: printf "%2\$d %1\$d", ...
(requires Perl 5.8.0 or newer)
jpayne@68: __expand("[new] replaces [old]", old => $oldvalue, new => $newvalue)
jpayne@68:
The libintl-perl
package is platform independent but is not
jpayne@68: part of the Perl core. The programmer is responsible for
jpayne@68: providing a dummy implementation of the required functions if the
jpayne@68: package is not installed on the target system.
jpayne@68:
— jpayne@68:
jpayne@68:Included in libintl-perl
, available on CPAN
jpayne@68: (https://www.cpan.org/).
jpayne@68:
An example is available in the ‘examples’ directory: hello-perl
.
jpayne@68:
The xgettext
parser backend for Perl differs significantly from
jpayne@68: the parser backends for other programming languages, just as Perl
jpayne@68: itself differs significantly from other programming languages. The
jpayne@68: Perl parser backend offers many more string marking facilities than
jpayne@68: the other backends but it also has some Perl specific limitations, the
jpayne@68: worst probably being its imperfectness.
jpayne@68:
It is often heard that only Perl can parse Perl. This is not true. jpayne@68: Perl cannot be parsed at all, it can only be executed. jpayne@68: Perl has various built-in ambiguities that can only be resolved at runtime. jpayne@68:
jpayne@68:The following example may illustrate one common problem: jpayne@68:
jpayne@68:print gettext "Hello World!"; jpayne@68: |
Although this example looks like a bullet-proof case of a function jpayne@68: invocation, it is not: jpayne@68:
jpayne@68:open gettext, ">testfile" or die; jpayne@68: print gettext "Hello world!" jpayne@68: |
In this context, the string gettext
looks more like a
jpayne@68: file handle. But not necessarily:
jpayne@68:
use Locale::Messages qw (:libintl_h); jpayne@68: open gettext ">testfile" or die; jpayne@68: print gettext "Hello world!"; jpayne@68: |
Now, the file is probably syntactically incorrect, provided that the module
jpayne@68: Locale::Messages
found first in the Perl include path exports a
jpayne@68: function gettext
. But what if the module
jpayne@68: Locale::Messages
really looks like this?
jpayne@68:
use vars qw (*gettext); jpayne@68: jpayne@68: 1; jpayne@68: |
In this case, the string gettext
will be interpreted as a file
jpayne@68: handle again, and the above example will create a file ‘testfile’
jpayne@68: and write the string “Hello world!” into it. Even advanced
jpayne@68: control flow analysis will not really help:
jpayne@68:
if (0.5 < rand) { jpayne@68: eval "use Sane"; jpayne@68: } else { jpayne@68: eval "use InSane"; jpayne@68: } jpayne@68: print gettext "Hello world!"; jpayne@68: |
If the module Sane
exports a function gettext
that does
jpayne@68: what we expect, and the module InSane
opens a file for writing
jpayne@68: and associates the handle gettext
with this output
jpayne@68: stream, we are clueless again about what will happen at runtime. It is
jpayne@68: completely unpredictable. The truth is that Perl has so many ways to
jpayne@68: fill its symbol table at runtime that it is impossible to interpret a
jpayne@68: particular piece of code without executing it.
jpayne@68:
Of course, xgettext
will not execute your Perl sources while
jpayne@68: scanning for translatable strings, but rather use heuristics in order
jpayne@68: to guess what you meant.
jpayne@68:
Another problem is the ambiguity of the slash and the question mark. jpayne@68: Their interpretation depends on the context: jpayne@68:
jpayne@68:# A pattern match. jpayne@68: print "OK\n" if /foobar/; jpayne@68: jpayne@68: # A division. jpayne@68: print 1 / 2; jpayne@68: jpayne@68: # Another pattern match. jpayne@68: print "OK\n" if ?foobar?; jpayne@68: jpayne@68: # Conditional. jpayne@68: print $x ? "foo" : "bar"; jpayne@68: |
The slash may either act as the division operator or introduce a
jpayne@68: pattern match, whereas the question mark may act as the ternary
jpayne@68: conditional operator or as a pattern match, too. Other programming
jpayne@68: languages like awk
present similar problems, but the consequences of a
jpayne@68: misinterpretation are particularly nasty with Perl sources. In awk
jpayne@68: for instance, a statement can never exceed one line and the parser
jpayne@68: can recover from a parsing error at the next newline and interpret
jpayne@68: the rest of the input stream correctly. Perl is different, as a
jpayne@68: pattern match is terminated by the next appearance of the delimiter
jpayne@68: (the slash or the question mark) in the input stream, regardless of
jpayne@68: the semantic context. If a slash is really a division sign but
jpayne@68: mis-interpreted as a pattern match, the rest of the input file is most
jpayne@68: probably parsed incorrectly.
jpayne@68:
There are certain cases, where the ambiguity cannot be resolved at all: jpayne@68:
jpayne@68:$x = wantarray ? 1 : 0; jpayne@68: |
The Perl built-in function wantarray
does not accept any arguments.
jpayne@68: The Perl parser therefore knows that the question mark does not start
jpayne@68: a regular expression but is the ternary conditional operator.
jpayne@68:
sub wantarrays {} jpayne@68: $x = wantarrays ? 1 : 0; jpayne@68: |
Now the situation is different. The function wantarrays
takes
jpayne@68: a variable number of arguments (like any non-prototyped Perl function).
jpayne@68: The question mark is now the delimiter of a pattern match, and hence
jpayne@68: the piece of code does not compile.
jpayne@68:
sub wantarrays() {} jpayne@68: $x = wantarrays ? 1 : 0; jpayne@68: |
Now the function is prototyped, Perl knows that it does not accept any
jpayne@68: arguments, and the question mark is therefore interpreted as the
jpayne@68: ternaray operator again. But that unfortunately outsmarts xgettext
.
jpayne@68:
The Perl parser in xgettext
cannot know whether a function has
jpayne@68: a prototype and what that prototype would look like. It therefore makes
jpayne@68: an educated guess. If a function is known to be a Perl built-in and
jpayne@68: this function does not accept any arguments, a following question mark
jpayne@68: or slash is treated as an operator, otherwise as the delimiter of a
jpayne@68: following regular expression. The Perl built-ins that do not accept
jpayne@68: arguments are wantarray
, fork
, time
, times
,
jpayne@68: getlogin
, getppid
, getpwent
, getgrent
,
jpayne@68: gethostent
, getnetent
, getprotoent
, getservent
,
jpayne@68: setpwent
, setgrent
, endpwent
, endgrent
,
jpayne@68: endhostent
, endnetent
, endprotoent
, and
jpayne@68: endservent
.
jpayne@68:
If you find that xgettext
fails to extract strings from
jpayne@68: portions of your sources, you should therefore look out for slashes
jpayne@68: and/or question marks preceding these sections. You may have come
jpayne@68: across a bug in xgettext
's Perl parser (and of course you
jpayne@68: should report that bug). In the meantime you should consider to
jpayne@68: reformulate your code in a manner less challenging to xgettext
.
jpayne@68:
In particular, if the parser is too dumb to see that a function jpayne@68: does not accept arguments, use parentheses: jpayne@68:
jpayne@68:$x = somefunc() ? 1 : 0; jpayne@68: $y = (somefunc) ? 1 : 0; jpayne@68: |
In fact the Perl parser itself has similar problems and warns you jpayne@68: about such constructs. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:Unless you instruct xgettext
otherwise by invoking it with one
jpayne@68: of the options --keyword
or -k
, it will recognize the
jpayne@68: following keywords in your Perl sources:
jpayne@68:
gettext
jpayne@68:
jpayne@68: dgettext:2
jpayne@68:
jpayne@68: The second argument will be extracted. jpayne@68:
jpayne@68:dcgettext:2
jpayne@68:
jpayne@68: The second argument will be extracted. jpayne@68:
jpayne@68:ngettext:1,2
jpayne@68:
jpayne@68: The first (singular) and the second (plural) argument will be jpayne@68: extracted. jpayne@68:
jpayne@68:dngettext:2,3
jpayne@68:
jpayne@68: The second (singular) and the third (plural) argument will be jpayne@68: extracted. jpayne@68:
jpayne@68:dcngettext:2,3
jpayne@68:
jpayne@68: The second (singular) and the third (plural) argument will be jpayne@68: extracted. jpayne@68:
jpayne@68:pgettext:1c,2
jpayne@68:
jpayne@68: The first (message context) and the second argument will be extracted. jpayne@68:
jpayne@68:dpgettext:2c,3
jpayne@68:
jpayne@68: The second (message context) and the third argument will be extracted. jpayne@68:
jpayne@68:dcpgettext:2c,3
jpayne@68:
jpayne@68: The second (message context) and the third argument will be extracted. jpayne@68:
jpayne@68:npgettext:1c,2,3
jpayne@68:
jpayne@68: The first (message context), second (singular), and third (plural) jpayne@68: argument will be extracted. jpayne@68:
jpayne@68:dnpgettext:2c,3,4
jpayne@68:
jpayne@68: The second (message context), third (singular), and fourth (plural) jpayne@68: argument will be extracted. jpayne@68:
jpayne@68:dcnpgettext:2c,3,4
jpayne@68:
jpayne@68: The second (message context), third (singular), and fourth (plural) jpayne@68: argument will be extracted. jpayne@68:
jpayne@68:gettext_noop
jpayne@68:
jpayne@68: %gettext
jpayne@68:
jpayne@68: The keys of lookups into the hash %gettext
will be extracted.
jpayne@68:
$gettext
jpayne@68:
jpayne@68: The keys of lookups into the hash reference $gettext
will be extracted.
jpayne@68:
Translating messages at runtime is normally performed by looking up the
jpayne@68: original string in the translation database and returning the
jpayne@68: translated version. The “natural” Perl implementation is a hash
jpayne@68: lookup, and, of course, xgettext
supports such practice.
jpayne@68:
print __"Hello world!"; jpayne@68: print $__{"Hello world!"}; jpayne@68: print $__->{"Hello world!"}; jpayne@68: print $$__{"Hello world!"}; jpayne@68: |
The above four lines all do the same thing. The Perl module
jpayne@68: Locale::TextDomain
exports by default a hash %__
that
jpayne@68: is tied to the function __()
. It also exports a reference
jpayne@68: $__
to %__
.
jpayne@68:
If an argument to the xgettext
option --keyword
,
jpayne@68: resp. -k
starts with a percent sign, the rest of the keyword is
jpayne@68: interpreted as the name of a hash. If it starts with a dollar
jpayne@68: sign, the rest of the keyword is interpreted as a reference to a
jpayne@68: hash.
jpayne@68:
Note that you can omit the quotation marks (single or double) around jpayne@68: the hash key (almost) whenever Perl itself allows it: jpayne@68:
jpayne@68:print $gettext{Error}; jpayne@68: |
The exact rule is: You can omit the surrounding quotes, when the hash
jpayne@68: key is a valid C (!) identifier, i.e. when it starts with an
jpayne@68: underscore or an ASCII letter and is followed by an arbitrary number
jpayne@68: of underscores, ASCII letters or digits. Other Unicode characters
jpayne@68: are not allowed, regardless of the use utf8
pragma.
jpayne@68:
Perl offers a plethora of different string constructs. Those that can
jpayne@68: be used either as arguments to functions or inside braces for hash
jpayne@68: lookups are generally supported by xgettext
.
jpayne@68:
print gettext "Hello World!"; jpayne@68: |
print gettext 'Hello World!'; jpayne@68: |
print gettext qq |Hello World!|; jpayne@68: print gettext qq <E-mail: <guido\@imperia.net>>; jpayne@68: |
The operator qq
is fully supported. You can use arbitrary
jpayne@68: delimiters, including the four bracketing delimiters (round, angle,
jpayne@68: square, curly) that nest.
jpayne@68:
print gettext q |Hello World!|; jpayne@68: print gettext q <E-mail: <guido@imperia.net>>; jpayne@68: |
The operator q
is fully supported. You can use arbitrary
jpayne@68: delimiters, including the four bracketing delimiters (round, angle,
jpayne@68: square, curly) that nest.
jpayne@68:
print gettext qx ;LANGUAGE=C /bin/date; jpayne@68: print gettext qx [/usr/bin/ls | grep '^[A-Z]*']; jpayne@68: |
The operator qx
is fully supported. You can use arbitrary
jpayne@68: delimiters, including the four bracketing delimiters (round, angle,
jpayne@68: square, curly) that nest.
jpayne@68:
The example is actually a useless use of gettext
. It will
jpayne@68: invoke the gettext
function on the output of the command
jpayne@68: specified with the qx
operator. The feature was included
jpayne@68: in order to make the interface consistent (the parser will extract
jpayne@68: all strings and quote-like expressions).
jpayne@68:
print gettext <<'EOF'; jpayne@68: program not found in $PATH jpayne@68: EOF jpayne@68: jpayne@68: print ngettext <<EOF, <<"EOF"; jpayne@68: one file deleted jpayne@68: EOF jpayne@68: several files deleted jpayne@68: EOF jpayne@68: |
Here-documents are recognized. If the delimiter is enclosed in single jpayne@68: quotes, the string is not interpolated. If it is enclosed in double jpayne@68: quotes or has no quotes at all, the string is interpolated. jpayne@68:
jpayne@68:Delimiters that start with a digit are not supported! jpayne@68:
jpayne@68:Perl is capable of interpolating variables into strings. This offers jpayne@68: some nice features in localized programs but can also lead to jpayne@68: problems. jpayne@68:
jpayne@68:A common error is a construct like the following: jpayne@68:
jpayne@68:print gettext "This is the program $0!\n"; jpayne@68: |
Perl will interpolate at runtime the value of the variable $0
jpayne@68: into the argument of the gettext()
function. Hence, this
jpayne@68: argument is not a string constant but a variable argument ($0
jpayne@68: is a global variable that holds the name of the Perl script being
jpayne@68: executed). The interpolation is performed by Perl before the string
jpayne@68: argument is passed to gettext()
and will therefore depend on
jpayne@68: the name of the script which can only be determined at runtime.
jpayne@68: Consequently, it is almost impossible that a translation can be looked
jpayne@68: up at runtime (except if, by accident, the interpolated string is found
jpayne@68: in the message catalog).
jpayne@68:
The xgettext
program will therefore terminate parsing with a fatal
jpayne@68: error if it encounters a variable inside of an extracted string. In
jpayne@68: general, this will happen for all kinds of string interpolations that
jpayne@68: cannot be safely performed at compile time. If you absolutely know
jpayne@68: what you are doing, you can always circumvent this behavior:
jpayne@68:
my $know_what_i_am_doing = "This is program $0!\n"; jpayne@68: print gettext $know_what_i_am_doing; jpayne@68: |
Since the parser only recognizes strings and quote-like expressions, jpayne@68: but not variables or other terms, the above construct will be jpayne@68: accepted. You will have to find another way, however, to let your jpayne@68: original string make it into your message catalog. jpayne@68:
jpayne@68:If invoked with the option --extract-all
, resp. -a
,
jpayne@68: variable interpolation will be accepted. Rationale: You will
jpayne@68: generally use this option in order to prepare your sources for
jpayne@68: internationalization.
jpayne@68:
Please see the manual page ‘man perlop’ for details of strings and jpayne@68: quote-like expressions that are subject to interpolation and those jpayne@68: that are not. Safe interpolations (that will not lead to a fatal jpayne@68: error) are: jpayne@68:
jpayne@68:\t
(tab, HT, TAB), \n
jpayne@68: (newline, NL), \r
(return, CR), \f
(form feed, FF),
jpayne@68: \b
(backspace, BS), \a
(alarm, bell, BEL), and \e
jpayne@68: (escape, ESC).
jpayne@68:
jpayne@68: \033
jpayne@68: use utf8
pragma.
jpayne@68:
jpayne@68: \x1b
jpayne@68:
jpayne@68: \x{263a}
jpayne@68: use utf8
pragma.
jpayne@68:
jpayne@68: \c[
(CTRL-[)
jpayne@68:
jpayne@68: \N{LATIN CAPITAL LETTER C WITH CEDILLA}
jpayne@68: use utf8
pragma.
jpayne@68: The following escapes are considered partially safe: jpayne@68:
jpayne@68:\l
lowercase next char
jpayne@68:
jpayne@68: \u
uppercase next char
jpayne@68:
jpayne@68: \L
lowercase till \E
jpayne@68:
jpayne@68: \U
uppercase till \E
jpayne@68:
jpayne@68: \E
end case modification
jpayne@68:
jpayne@68: \Q
quote non-word characters till \E
jpayne@68:
jpayne@68: These escapes are only considered safe if the string consists of
jpayne@68: ASCII characters only. Translation of characters outside the range
jpayne@68: defined by ASCII is locale-dependent and can actually only be performed
jpayne@68: at runtime; xgettext
doesn't do these locale-dependent translations
jpayne@68: at extraction time.
jpayne@68:
Except for the modifier \Q
, these translations, albeit valid,
jpayne@68: are generally useless and only obfuscate your sources. If a
jpayne@68: translation can be safely performed at compile time you can just as
jpayne@68: well write what you mean.
jpayne@68:
Perl is often used to generate sources for other programming languages jpayne@68: or arbitrary file formats. Web applications that output HTML code jpayne@68: make a prominent example for such usage. jpayne@68:
jpayne@68:You will often come across situations where you want to intersperse jpayne@68: code written in the target (programming) language with translatable jpayne@68: messages, like in the following HTML example: jpayne@68:
jpayne@68:print gettext <<EOF; jpayne@68: <h1>My Homepage</h1> jpayne@68: <script language="JavaScript"><!-- jpayne@68: for (i = 0; i < 100; ++i) { jpayne@68: alert ("Thank you so much for visiting my homepage!"); jpayne@68: } jpayne@68: //--></script> jpayne@68: EOF jpayne@68: |
The parser will extract the entire here document, and it will appear jpayne@68: entirely in the resulting PO file, including the JavaScript snippet jpayne@68: embedded in the HTML code. If you exaggerate with constructs like jpayne@68: the above, you will run the risk that the translators of your package jpayne@68: will look out for a less challenging project. You should consider an jpayne@68: alternative expression here: jpayne@68:
jpayne@68:print <<EOF; jpayne@68: <h1>$gettext{"My Homepage"}</h1> jpayne@68: <script language="JavaScript"><!-- jpayne@68: for (i = 0; i < 100; ++i) { jpayne@68: alert ("$gettext{'Thank you so much for visiting my homepage!'}"); jpayne@68: } jpayne@68: //--></script> jpayne@68: EOF jpayne@68: |
Only the translatable portions of the code will be extracted here, and jpayne@68: the resulting PO file will begrudgingly improve in terms of readability. jpayne@68:
jpayne@68:You can interpolate hash lookups in all strings or quote-like jpayne@68: expressions that are subject to interpolation (see the manual page jpayne@68: ‘man perlop’ for details). Double interpolation is invalid, however: jpayne@68:
jpayne@68:# TRANSLATORS: Replace "the earth" with the name of your planet. jpayne@68: print gettext qq{Welcome to $gettext->{"the earth"}}; jpayne@68: |
The qq
-quoted string is recognized as an argument to xgettext
in
jpayne@68: the first place, and checked for invalid variable interpolation. The
jpayne@68: dollar sign of hash-dereferencing will therefore terminate the parser
jpayne@68: with an “invalid interpolation” error.
jpayne@68:
It is valid to interpolate hash lookups in regular expressions: jpayne@68:
jpayne@68:if ($var =~ /$gettext{"the earth"}/) { jpayne@68: print gettext "Match!\n"; jpayne@68: } jpayne@68: s/$gettext{"U. S. A."}/$gettext{"U. S. A."} $gettext{"(dial +0)"}/g; jpayne@68: |
In Perl, parentheses around function arguments are mostly optional.
jpayne@68: xgettext
will always assume that all
jpayne@68: recognized keywords (except for hashes and hash references) are names
jpayne@68: of properly prototyped functions, and will (hopefully) only require
jpayne@68: parentheses where Perl itself requires them. All constructs in the
jpayne@68: following example are therefore ok to use:
jpayne@68:
print gettext ("Hello World!\n"); jpayne@68: print gettext "Hello World!\n"; jpayne@68: print dgettext ($package => "Hello World!\n"); jpayne@68: print dgettext $package, "Hello World!\n"; jpayne@68: jpayne@68: # The "fat comma" => turns the left-hand side argument into a jpayne@68: # single-quoted string! jpayne@68: print dgettext smellovision => "Hello World!\n"; jpayne@68: jpayne@68: # The following assignment only works with prototyped functions. jpayne@68: # Otherwise, the functions will act as "greedy" list operators and jpayne@68: # eat up all following arguments. jpayne@68: my $anonymous_hash = { jpayne@68: planet => gettext "earth", jpayne@68: cakes => ngettext "one cake", "several cakes", $n, jpayne@68: still => $works, jpayne@68: }; jpayne@68: # The same without fat comma: jpayne@68: my $other_hash = { jpayne@68: 'planet', gettext "earth", jpayne@68: 'cakes', ngettext "one cake", "several cakes", $n, jpayne@68: 'still', $works, jpayne@68: }; jpayne@68: jpayne@68: # Parentheses are only significant for the first argument. jpayne@68: print dngettext 'package', ("one cake", "several cakes", $n), $discarded; jpayne@68: |
The necessity of long messages can often lead to a cumbersome or
jpayne@68: unreadable coding style. Perl has several options that may prevent
jpayne@68: you from writing unreadable code, and
jpayne@68: xgettext
does its best to do likewise. This is where the dot
jpayne@68: operator (the string concatenation operator) may come in handy:
jpayne@68:
print gettext ("This is a very long" jpayne@68: . " message that is still" jpayne@68: . " readable, because" jpayne@68: . " it is split into" jpayne@68: . " multiple lines.\n"); jpayne@68: |
Perl is smart enough to concatenate these constant string fragments
jpayne@68: into one long string at compile time, and so is
jpayne@68: xgettext
. You will only find one long message in the resulting
jpayne@68: POT file.
jpayne@68:
Note that the future Perl 6 will probably use the underscore
jpayne@68: (‘_’) as the string concatenation operator, and the dot
jpayne@68: (‘.’) for dereferencing. This new syntax is not yet supported by
jpayne@68: xgettext
.
jpayne@68:
If embedded newline characters are not an issue, or even desired, you jpayne@68: may also insert newline characters inside quoted strings wherever you jpayne@68: feel like it: jpayne@68:
jpayne@68:print gettext ("<em>In HTML output jpayne@68: embedded newlines are generally no jpayne@68: problem, since adjacent whitespace jpayne@68: is always rendered into a single jpayne@68: space character.</em>"); jpayne@68: |
You may also consider to use here documents: jpayne@68:
jpayne@68:print gettext <<EOF; jpayne@68: <em>In HTML output jpayne@68: embedded newlines are generally no jpayne@68: problem, since adjacent whitespace jpayne@68: is always rendered into a single jpayne@68: space character.</em> jpayne@68: EOF jpayne@68: |
Please do not forget that the line breaks are real, i.e. they jpayne@68: translate into newline characters that will consequently show up in jpayne@68: the resulting POT file. jpayne@68:
jpayne@68: jpayne@68: jpayne@68: jpayne@68:The foregoing sections should have proven that
jpayne@68: xgettext
is quite smart in extracting translatable strings from
jpayne@68: Perl sources. Yet, some more or less exotic constructs that could be
jpayne@68: expected to work, actually do not work.
jpayne@68:
One of the more relevant limitations can be found in the jpayne@68: implementation of variable interpolation inside quoted strings. Only jpayne@68: simple hash lookups can be used there: jpayne@68:
jpayne@68:print <<EOF; jpayne@68: $gettext{"The dot operator" jpayne@68: . " does not work" jpayne@68: . "here!"} jpayne@68: Likewise, you cannot @{[ gettext ("interpolate function calls") ]} jpayne@68: inside quoted strings or quote-like expressions. jpayne@68: EOF jpayne@68: |
This is valid Perl code and will actually trigger invocations of the
jpayne@68: gettext
function at runtime. Yet, the Perl parser in
jpayne@68: xgettext
will fail to recognize the strings. A less obvious
jpayne@68: example can be found in the interpolation of regular expressions:
jpayne@68:
s/<!--START_OF_WEEK-->/gettext ("Sunday")/e; jpayne@68: |
The modifier e
will cause the substitution to be interpreted as
jpayne@68: an evaluable statement. Consequently, at runtime the function
jpayne@68: gettext()
is called, but again, the parser fails to extract the
jpayne@68: string “Sunday”. Use a temporary variable as a simple workaround if
jpayne@68: you really happen to need this feature:
jpayne@68:
my $sunday = gettext "Sunday"; jpayne@68: s/<!--START_OF_WEEK-->/$sunday/; jpayne@68: |
Hash slices would also be handy but are not recognized: jpayne@68:
jpayne@68:my @weekdays = @gettext{'Sunday', 'Monday', 'Tuesday', 'Wednesday', jpayne@68: 'Thursday', 'Friday', 'Saturday'}; jpayne@68: # Or even: jpayne@68: @weekdays = @gettext{qw (Sunday Monday Tuesday Wednesday Thursday jpayne@68: Friday Saturday) }; jpayne@68: |
This is perfectly valid usage of the tied hash %gettext
but the
jpayne@68: strings are not recognized and therefore will not be extracted.
jpayne@68:
Another caveat of the current version is its rudimentary support for jpayne@68: non-ASCII characters in identifiers. You may encounter serious jpayne@68: problems if you use identifiers with characters outside the range of jpayne@68: 'A'-'Z', 'a'-'z', '0'-'9' and the underscore '_'. jpayne@68:
jpayne@68:Maybe some of these missing features will be implemented in future jpayne@68: versions, but since you can always make do without them at minimal effort, jpayne@68: these todos have very low priority. jpayne@68:
jpayne@68:A nasty problem are brace format strings that already contain braces jpayne@68: as part of the normal text, for example the usage strings typically jpayne@68: encountered in programs: jpayne@68:
jpayne@68:die "usage: $0 {OPTIONS} FILENAME...\n"; jpayne@68: |
If you want to internationalize this code with Perl brace format strings, jpayne@68: you will run into a problem: jpayne@68:
jpayne@68:die __x ("usage: {program} {OPTIONS} FILENAME...\n", program => $0); jpayne@68: |
Whereas ‘{program}’ is a placeholder, ‘{OPTIONS}’
jpayne@68: is not and should probably be translated. Yet, there is no way to teach
jpayne@68: the Perl parser in xgettext
to recognize the first one, and leave
jpayne@68: the other one alone.
jpayne@68:
There are two possible work-arounds for this problem. If you are
jpayne@68: sure that your program will run under Perl 5.8.0 or newer (these
jpayne@68: Perl versions handle positional parameters in printf()
) or
jpayne@68: if you are sure that the translator will not have to reorder the arguments
jpayne@68: in her translation – for example if you have only one brace placeholder
jpayne@68: in your string, or if it describes a syntax, like in this one –, you can
jpayne@68: mark the string as no-perl-brace-format
and use printf()
:
jpayne@68:
# xgettext: no-perl-brace-format jpayne@68: die sprintf ("usage: %s {OPTIONS} FILENAME...\n", $0); jpayne@68: |
If you want to use the more portable Perl brace format, you will have to do jpayne@68: put placeholders in place of the literal braces: jpayne@68:
jpayne@68:die __x ("usage: {program} {[}OPTIONS{]} FILENAME...\n", jpayne@68: program => $0, '[' => '{', ']' => '}'); jpayne@68: |
Perl brace format strings know no escaping mechanism. No matter how this
jpayne@68: escaping mechanism looked like, it would either give the programmer a
jpayne@68: hard time, make translating Perl brace format strings heavy-going, or
jpayne@68: result in a performance penalty at runtime, when the format directives
jpayne@68: get executed. Most of the time you will happily get along with
jpayne@68: printf()
for this special case.
jpayne@68:
mod_php4, mod_php4-core, phpdoc jpayne@68:
jpayne@68:php jpayne@68:
jpayne@68:php
, php3
, php4
jpayne@68:
"abc"
, 'abc'
jpayne@68:
_("abc")
jpayne@68:
gettext
, dgettext
, dcgettext
; starting with PHP 4.2.0
jpayne@68: also ngettext
, dngettext
, dcngettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
Programmer must call setlocale (LC_ALL, "")
jpayne@68:
— jpayne@68:
jpayne@68:use jpayne@68:
jpayne@68:xgettext
jpayne@68:
printf "%2\$d %1\$d"
jpayne@68:
On platforms without gettext, the functions are not available. jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-php
.
jpayne@68:
roxen jpayne@68:
jpayne@68:pike8.0 or pike7.8 jpayne@68:
jpayne@68:pike
jpayne@68:
"abc"
jpayne@68:
— jpayne@68:
jpayne@68:gettext
, dgettext
, dcgettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
setlocale
function
jpayne@68:
import Locale.Gettext;
jpayne@68:
use jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:On platforms without gettext, the functions are not available. jpayne@68:
jpayne@68:— jpayne@68:
gcc jpayne@68:
jpayne@68:gcc jpayne@68:
jpayne@68:c
, h
.
jpayne@68:
"abc"
jpayne@68:
_("abc")
jpayne@68:
gettext
, dgettext
, dcgettext
, ngettext
,
jpayne@68: dngettext
, dcngettext
jpayne@68:
textdomain
function
jpayne@68:
bindtextdomain
function
jpayne@68:
Programmer must call setlocale (LC_ALL, "")
jpayne@68:
#include "intl.h"
jpayne@68:
Use jpayne@68:
jpayne@68:xgettext -k_
jpayne@68:
— jpayne@68:
jpayne@68:Uses autoconf macros jpayne@68:
jpayne@68:yes jpayne@68:
libycp, libycp-devel, yast2-core, yast2-core-devel jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:ycp
jpayne@68:
"abc"
jpayne@68:
_("abc")
jpayne@68:
_()
with 1 or 3 arguments
jpayne@68:
textdomain
statement
jpayne@68:
— jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:— jpayne@68:
jpayne@68:use jpayne@68:
jpayne@68:xgettext
jpayne@68:
sformat "%2 %1"
jpayne@68:
fully portable jpayne@68:
jpayne@68:— jpayne@68:
An example is available in the ‘examples’ directory: hello-ycp
.
jpayne@68:
[ << ] | jpayne@68:[ >> ] | jpayne@68:jpayne@68: | jpayne@68: | jpayne@68: | jpayne@68: | jpayne@68: | [Top] | jpayne@68:[Contents] | jpayne@68:[Index] | jpayne@68:[ ? ] | jpayne@68:
jpayne@68:
jpayne@68: This document was generated by Bruno Haible on February, 21 2024 using texi2html 1.78a.
jpayne@68:
jpayne@68:
jpayne@68:
jpayne@68: