Note: This is taken from the Chicken Wiki, where a more recent version could be available.


This egg is a Chicken Scheme port of Locale::MakeText; see

To save you the trouble of reading that document, the goal is to provide an easy to use localization system that actually works once you start trying to do complicated things in more than 2 languages or so.

If you have any problems with this egg, or would like to suggest changes/additions to the documentation, please e-mail

Function Documentation

This is the general documentation, containing examples, background, and so on. The function documentation is generated from the source using mole, and can be found at

Differences From Locale::MakeText

Because of the history behind Common Lisp's format function, which Scheme has inherited, we don't use the same escape sequences.

Strings are not turned into code at all, because with the 2-pass setup I'd need to be able to get code back from format-modular, and I can't. This is a possible target for future optimization, if this module causes performance problems.

caketext can write out auto-generated language packs; nah-nah, our language has code/data isomorphism and yooooours doesn't! :) (More to the point, all Schemes can read/write almost all Scheme objects on the fly; it's a basic part of the language.)


Also because of wanting to use a CL-style format, this egg requires format-modular (also, format-modular has some nice modularity this egg takes advantage of). If you want to compile it yourself and run the test suite, you'll need testbase-driver and all of its requirements.

Configuration Values

Function to run when a miss occurs on this pack. Arguments passed are the language pack and the text key. No other packs are checked. The value returned is used as the translated text.
Boolean; if true and there's a miss on this pack, add the string here. No other packs are checked.

Neither of these have any kind of fall-through options because I couldn't think of a case where that would be useful. If you have a real-world examples, please let me know.

Escape Sequences

We use format-modular, and the processing of escapes is done in 2 passes. The first pass is a regular format-modular "format" pass, and all those escapes apply and are dealt with.

The second pass uses our own function escapes, which are like so:


(the [...] are indicating optionality; they are not literal)


"This is a test string: %(test%,~A%,~A%)."

Given a function stored with the name 'test in the appropriate language pack, this would run that test function on the next two caketext-translate arguments, i.e. ~A and ~A, which have already been substituted by the first pass, and replace the whole %(...%) string with the results.

Dumping And Loading

At any time, the strings in a language pack can be dumped out to a file using dump-language-pack. Unlike srfi-29, no attempt is made to decide what the file should be named; that's up to you.

Also at any time, a file full of an alist of strings can be loaded back into a language pack using load-language-pack. If you do so, it completely replaces the pack's current strings.

Similarily, you can load a file full of an alist of symbols and function definitons to replace the function definitions of a pack. The performance implications of doing so are non-trivial; see the documentation for the load-language-pack function for alternatives.


A lot of examples can be found by looking at caketext-spec.scm, which is the test suite. Here's an example of normal usage; please e-mail me ( if it is insufficient for you.

 (define english-pack (new-language-pack))

 (set-language-pack-config! english-pack 'auto-add #t)


   (caketext-translate english-pack #f "You found ~A files." number))

This will render the output unchanged; that is, at this point you might as well have used (format ...), except that the string has been stored for future translation, which is yay.


 (dump-language-pack "/tmp/english-strings.dump")

In that file your translator will find something like this (we pretty-print; lucky you):

 (("You found ~A files."
   "You found ~A files."))

Your translator should edit that file, perhaps to look something like this:

 (("You found ~A files."
   "You found ~A files, eh?"))

and saves it to a file named, say, /tmp/canadian-strings.dump

After this is done, to localize your program to Canadian English you'd put statements like this at the top:

 (define canadian-pack (new-language-pack))

 (load-language-pack canadian-pack "/tmp/canadian-strings.dump" "")


   (caketext-translate english-pack #f "You found ~A files." number))

Given the number 5, this will output:

You found 5 files, eh?

License And Copyright

This entire egg (this file, the test cases, and the documentation) are all explicitely placed in the public domain by me, Robin Lee Powell, on 10 March 2008. If you like the software, I'd sure appreciate a note, or a line of thanks in your own code or whatever, but if you do so be sure to thank Andy Lester, the Locale::Maketext guy, as well, as this is basically copycat work.