You are looking at historical revision 4540 of this page. It may differ significantly from its current revision.

PPtags: eggPP

free-gettext is a drop-in compatible replacement for the gettext egg implemented from scratch purely in Scheme and thus available with a BSD license. free-gettext is also easier to use allowing you to optionally load .po files directly without compiling them to .mo files first and has many advanced features such as multi-language locales and cascaded message domains.


000 Introduction

'''procedure:''' (textdomain P0name0P)
'''procedure:''' (gettext 0message0)

0enscript highlight0scheme0 (use free-gettext) (textdomain "myapp") (print (gettext "Hello world!")) 0/enscript0

The above is the most basic usage and is equivalent to the GNU gettext module. TEXTDOMAIN sets the name of the current "domain" which is the name of the message catalog (typically the name of the application). With no arguments it returns the name of that domain. GETTEXT then fetches the translation of the message in that domain in the current locale (from the LANG environment variable) or returns the original string if the message can't be found.

Apart from actually creating the message files (which you can put off indefinitely) that's all you need to internationalize your message strings. Since every natural language string needs to be translated a common idiom is to give a short name to GETTEXT:

0enscript highlight0scheme0 (define _ gettext) (print (_"Hello world!")) 0/enscript0

Alternately you could make a prefix for all message strings:

0enscript highlight0scheme0 (define-syntax unquote

 (syntax-rules ()
   ((_ str) (gettext str))))

(print "Hello world!") 0/enscript0

Note that free-gettext converts all strings to utf8 internally to work best with the utf8 egg and other eggs which assume Chicken strings are utf8. This is a feature - all strings are consistently the same encoding and you don't need to create separate message files for every different encoding a user might want. Many GUI toolkits like Gtk also assume utf8. On the other hand if you want to output text to a non-utf8 terminal you'll need to perform the translation manually.

0000 Plural forms

There is also a procedure NGETTEXT for working with plural forms:

'''procedure:''' (ngettext 0msg-singular0 0msg-plural0 0n0)

0enscript highlight0scheme0 (format #t (ngettext "pD file removed" "pD files removed" n) n) 0/enscript0

In the case of English (or if no translation is found) this applies the familiar logic of using the first string (singular) if N is 1 and the second string (plural) otherwise. Not all languages have two plural forms however and the NGETTEXT interface allows you to write message files with the proper inflections for any language and any value of N. The exact details of how to write a message file is beyond the scope of this document - see the GNU gettext documentation.

0000 Multiple Domains

As with GNU gettext the following are provided:

'''procedure:''' (dgettext 0domain0 0message0)
'''procedure:''' (dcgettext 0domain0 0message0 0locale0)
'''procedure:''' (dngettext 0domain0 0msg-singular0 0msg-plural0 0n0)
'''procedure:''' (dcngettext 0domain0 0msg-singular0 0msg-plural0 0n0 0locale0)

These let you lookup messages in domains other than that specified by TEXTDOMAIN. This is just a clumsy way to make up for inadequacies in the traditional gettext design - if you want to work with multiple domains you should use the cascaded domains described below.

'''procedure:''' (bindtextdomain 0domain0 0dirname0)

Override the directory to look for the given domain in.

000 Cascaded Domains

A major inconvenience of gettext is that it's essentially a one message file per application design. Related applications applications with the same menu entries or same error messages all of these need to have their own duplicated translations of all the same messages.

free-gettext however lets you specify a list of strings as the text domain and for any message lookup these domains are searched in order.

0enscript highlight0scheme0 (textdomain '("myapp" "gimp")) 0 search 1st myapp then gimp (gettext "/File/Close") 0 "Close" from gimp unless overridden 0/enscript0

You can thus share messages freely between applications and effectively have collections of message dictionaries.

000 First-class Lookup Interface

One of the most common types of application to write these days is a web application for which gettext is poorly suited. Gettext assumes a single locale but for any kind of server the clients may each have their own locale. free-gettext therefore provides a way to generate separate first class gettext procedures.

'''procedure:''' (make-gettext domain PlocaleP PdirsP PcdirP Pcached0P Plookup-cached0P)

DOMAIN is the same as the first argument to TEXTDOMAIN and may be similarly cascaded.

LOCALE is the locale as a string or list of strings of the form LANGP_REGIONPP.ENCODINGP and defaults to the LANG or LC_ALL environment variable or C if neither is set. Multiple locales are also searched in order which can be useful when you have incomplete translations in similar languages.

DIRS (again a string or list of strings) is the search path of directories which should hold the LOCALE/CDIR/ directories which contain the actual message catalogs. This is always appended with the system default e.g. "/usr/share/locale" and may also inherit from the GETTEXT_PATH colon-delimited environment variable.

CDIR is the catagory directory defaulting to either the LC_CATEGORY environment variable or the appropriate system default (e.g. LC_MESSAGES). You generally won't need to specify this.

CACHED0 means to cache individual messages and defaults to #t. This is a natural default (GNU gettext similarly caches messages) but during development it can be handy to disable caching if you intend to edit messages while coding.

LOOKUP-CACHED0 means to cache the lookup dispatch generated by these parameters and defaults to #t. Thus by default multiple calls to MAKE-GETTEXT with the same parameters return the same object and they in turn share the same message cache.

MAKE-GETTEXT returns a dispatch closure with the following parameters:

0000 Procedures

 (0self0 'getter) - returns a gettext-style procedure
 (0self0 'ngetter) - returns an ngettext-style procedure
 (0self0 'setter) - returns a procedure for manually setting message translations

0000 Actions

 (0self0 'get 0message0) 00 ((0self0 'getter) 0message0)
 (0self0 'nget 0msg-singular0 0msg-plural0 0n0) 00 ((0self0 'ngetter) 0msg-singular0 0msg-plural0 0n0)
 (0self0 'set! 0message0 0value0) 00 ((0self0 'set!) 0message0 0value0)

0000 Accessors

 (0self0 'locale)
 (0self0 'domain)
 (0self0 'dirs)
 (0self0 'files)

0000 Cache management

 (0self0 'use-cache 0true-or-false0) - enable or disable message caching
 (0self0 'clear) - clears the cache

Note that TEXTDOMAIN actually accepts all of the same parameters as MAKE-GETTEXT so that you can specify the locale and other settings manually if you want.

000 Quick Start Tutorial

 (use free-gettext)
 Replace any messages with (gettext 0message0) or a shortcut.
 Generate the .po file with the command "xgettext myapp.scm".
  If you use a shortcut its "xgettext --keyword0_ myapp.scm".
  The -a parameter will extract _all_ strings.
  The default output is messages.po  but the -d0name0 parameter overrides this.
 Make a "locale" subdirectory tree  and move the file to "./locale/en/LC_MESSAGES/myapp.po".
 When testing  "export GETTEXT_PATH0./locale/" so it can access the uninstalled files.
 Optionally  compile the .po with the "msgfmt" command.
 Write your .setup file to install the locale files in /usr/share/locale/.

000 Why Gettext0

Because you need some file format for your messages and gettext is widely recognized and has extensive tool support.

000 Requirements



000 Author

PPAlex ShinnPP

000 License


000 History

0 1.0 : initial release