gettext
1 Introduction
textdomain
gettext
2 Plural forms
ngettext
3 Multiple Domains
dgettext
dcgettext
dngettext
dcngettext
bindtextdomain
4 Cascaded Domains
5 Context support
pgettext
dpgettext
dcpgettext
npgettext
6 First-class Lookup Interface
make-gettext
6.1 Procedures
6.2 Actions
6.3 Accessors
6.4 Cache management
7 Quick Start Tutorial
8 Why Gettext?
9 License
7.7

gettext

Roman Klochkov <kalimehtar@mail.ru>

 (require gettext) package: gettext

1 Introduction

This package is an implementation of GNU gettext. It is implemented from scratch purely in Scheme and thus available with a BSD license. It 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.

(require gettext)
(textdomain "myapp")
(print (gettext "Hello, world!"))

The above is the most basic usage and is equivalent to the GNU gettext module.

procedure

(textdomain name    
  [#:locale locale    
  #:dirs dirs    
  #:cdir cdir    
  #:cached cached?    
  #:lookup-cached? lookup-cached?])  procedure?
  name : (or/c string? (listof string?))
  locale : (or/c #f string? (listof string?)) = #f
  dirs : (or/c #f path-string? (listof path-string?)) = #f
  cdir : (or/c #f string?) = #f
  cached? : boolean? = #t
  lookup-cached? : boolean? = #t
(textdomain)  string?
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. For the rest arguments see make-gettext.

procedure

(gettext message)  string?

  message : string?
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:

(define _ gettext)
(print (_"Hello, world!"))

Alternately, you could make “,” a prefix for all message strings:

(define-syntax unquote
  (syntax-rules ()
    ((_ str) (gettext str))))
 
(print ,"Hello, world!")

2 Plural forms

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

procedure

(ngettext msg-singular msg-plural n)  string?

  msg-singular : string?
  msg-plural : string?
  n : number?

(format #t (ngettext "~D file removed" "~D files removed" n) n)

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.

3 Multiple Domains

As with GNU gettext, the following are provided:

procedure

(dgettext domain message)  string?

  domain : (or/c string? (listof string?))
  message : string?

procedure

(dcgettext domain message category)  string?

  domain : (or/c string? (listof string?))
  message : string?
  category : string?

procedure

(dngettext domain msg-singular msg-plural n)  string?

  domain : (or/c string? (listof string?))
  msg-singular : string?
  msg-plural : string?
  n : number?

procedure

(dcngettext domain    
  msg-singular    
  msg-plural    
  n    
  category)  string?
  domain : (or/c string? (listof string?))
  msg-singular : string?
  msg-plural : string?
  n : number?
  category : string?

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 domain dirname)  void?

  domain : string?
  dirname : string?
Override the directory to look for the given domain in.

4 Cascaded Domains

A major inconvenience of GNU 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.

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

(textdomain '("myapp" "gimp"))  ; search 1st myapp, then gimp
(gettext "/File/Close")         ; "Close" from gimp unless overridden

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

5 Context support

As with GNU gettext, functions for translation with context:

procedure

(pgettext msgctxt msgid)  string?

  msgctxt : string?
  msgid : string?
Returns the translation of msgid, restricted to the context given by msgctxt.

procedure

(dpgettext domain msgctxt msgid)  string?

  domain : string?
  msgctxt : string?
  msgid : string?

procedure

(dcpgettext domain msgctxt msgid category)  string?

  domain : string?
  msgctxt : string?
  msgid : string?
  category : string?
These are generalizations of pgettext. They behave similarly to dgettext and dcgettext, respectively. The domain argument defines the translation domain. The category argument allows to use another locale category than LC_MESSAGES.

procedure

(npgettext msgctxt msg-singular msg-plural n)  string?

  msgctxt : string?
  msg-singular : string?
  msg-plural : string?
  n : number?
This is ngettext with context.

6 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    
  [#:locale locale    
  #:dirs dirs    
  #:cdir cdir    
  #:cached cached?    
  #:lookup-cached? lookup-cached?])  procedure?
  domain : (or/c string? (listof string?))
  locale : (or/c #f string? (listof string?)) = #f
  dirs : (or/c #f path-string? (listof path-string?)) = #f
  cdir : (or/c #f string?) = #f
  cached? : boolean? = #t
  lookup-cached? : boolean? = #t
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 LANG[_REGION][.ENCODING], 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 category 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.

cached? 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-cached? 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:

6.1 Procedures

6.2 Actions

6.3 Accessors

6.4 Cache management

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.

7 Quick Start Tutorial

8 Why Gettext?

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

9 License

BSD