Version 63 of msgcat

Updated 2012-07-17 09:42:20 by oehhar

Purpose: information relating to the message catalog interface.


Documentation can be found at http://www.purl.org/tcl/home/man/tcl8.5/TclCmd/msgcat.htm


The msgcat package (standard with Tcl since 8.1) addresses the problem of hard coded application text.

Instead of

 label .x -text Files

if you write

 label .x -text [mc Files]

then you can create catalog entries for various languages for the term "Files". Also, mc will apply formatting to the string, so

 puts [mc "Directory contains %d files" $nfiles]

will allow a translator to work with the string "Directory contains %d files".

The above example assumes you have once invoked

 package require msgcat ;# and done 
 namespace import msgcat::* ;# (or msgcat::mc).

Provided you have .msg files containing

 ::msgcat::mcset de Files Dateien
 ::msgcat::mcset fr Files Fichiers

(notice that the rootname part has the naming convention that it shall be the contained language - for e.g. locale "en_us_funky", msgcat searches the contents of first en_us_funky.msg, then en_us.msg, then en.msg) then either automagically (when env(LANG) is accordingly set) or by

 ::msgcat::mclocale fr

.x will have the text "Fichiers".

If you want to package your messages into the application file, you can as well do this with mcset. See Multilingual menu and A little stopwatch for examples.

Note that msgcat 1.3 (comes with Tcl 8.4) also initializes the locale from ::env(LC_ALL) or ::env(LC_MESSAGES).

LES: I don't have ::env(LC_ALL) and ::env(LC_MESSAGES) on Slackware 11.


Arjen Markus This came up in the newsgroup:

The utility frink is able to adjust the source code so that the new code uses the msgcat package.


The 8.3.4 release of the PPC binary is broken in that it lacks msgcat and bgerror implementations. Melissa Schrumpf explains the situation with her customary clarity

    ... bgerror and msgcat are contained in tcl/library/msgcat/msgcat.tcl.

    Do this:

    Copy "Simply Tk (PPC)" to "Simply Tk (PPC).edit"

    Run ResEdit (or Resourcer, or whathaveyou).  Open a "Simply Tk
    (PPC).edit" in ResEdit.  Open the "TEXT" resources.  Open resource ID
       "package require msgcat"

    This will be right at the top.

    Next, open tcl/library/msgcat/msgcat.tcl in a text editor.  Copy from
    the beginning of the line:

       package provide msgcat 1.1.1  




    through to the end of the file.

    Return to ResEdit.  Delete the line "package require msgcat" and,
    in its place, paste the code you copied from msgcat.tcl.
    Close all resources and save.

    You now have a fixed stand-alone Tk shell.      

Anton Kovalenko has written, "Also, there is a small but useful script, which converts non-ascii characters from current system encoding to \uXXXX sequences. I think it would be useful to anyone who works often with tcl message catalogs. http://kovalenko.webzone.ru/unicodize.tcl (A/AK: chat.ru is down, so my page migrated) "

LES: "Forbidden. You don't have permission to access /unicodize.tcl on this server."


A/AK: there are some things about msgcat and shortcut keys, that are important for GUI application writers. EKB And this seems to have been continued into ampersand magic.


KHM Any Idea where to download this tool?

LV KHM - msgcat is a part of Tcl itself. Or are you talking about some other tool?


GNU gettext has support (since V 0.13 [L1 ]) for Tcl msgcat and conversion tools from and to PO format. http://ftp.gnu.org/gnu/gettext/


Simple Tk example of switching languages, complements of dgp:

 package require Tk

 bgerror 123

 msgcat::mclocale "fr"
 msgcat::mcload [file join $::tk_library msgs]
 bgerror 123
 
 msgcat::mclocale "en_gb"
 msgcat::mcload [file join $::tk_library msgs]
 bgerror 123

Now, how can I determine what languages are available for mclocale?


escargo 8 Dec 2003 - What if you want to do some form of parameter substitution in the strings that you might use with msgcat? In some systems I have developed, messages were somewhat macro-like; you might pass a number or a name (of a file, for example) that should be part of the message. Is there anything in the msgcat that does the substitution internally, or do I have to add my own layer on top of it?

RS: Easy, for instance with format:

 msgcat::mcset fr "Directory contains %d files" "Il y a %d fichiers"
 ...
 puts [format [mc "Directory contains %d files"] $nfiles]

DGP Even easier. There's a format already built-in to mc:

 puts [mc "Directory contains %d files" $nfiles]

EKB I moved this example up to the top of the page and combined it with the intro text so it's easier to find.

AM Also very useful: the %1$s type format codes - with this you can interchange variables if needed.

  % mc "this is a %s test for %s" first anything
  this is a first test for anything
 
  % mc {this is a %2$s test for %1$s} first anything
  this is a anything test for first

Note the {} around the text to prevent the $ to be interpreted and looking for the variable $s.


RS 2007-01-08: Here's a simple self-contained example for testing:

 #!/usr/bin/env tclsh
 package require msgcat

 msgcat::mcset de yes Ja
 msgcat::mcset de no  Nein
 msgcat::mcset fr yes Oui
 msgcat::mcset fr no  Non

 proc localbool value {
    if {$value} {msgcat::mc yes} else {msgcat::mc no}
 }
 puts [localbool 0]/[localbool 1]
That's all. Save that to a file, and run it with different LANG settings:
 $ /Tcl/msgcat.tcl
 Nein/Ja
 $ LANG=fr /Tcl/msgcat.tcl
 Non/Oui
 $ LANG=en /Tcl/msgcat.tcl
 no/yes

HaO 2010-04-07: Switching locale at runtime

msgcat::mcload only loads the message files required by the current locale. Given a locale de_CH (swiss german), the following files will be loaded: de_ch.msg, de.msg and ROOT.msg.

Example

An application is localised in german, french and, as default, english.

msg file setup

Each namespace has a folder containing the following files:

  • de.msg : german translation
  • fr.msg : french translation
  • ROOT.msg : english translation as default

load message catalogues

Within each namespace, the following commands must be executed:

msgcat::mclocale de
msgcat::mcload <path>
msgcat::mclocale fr
msgcat::mcload <path>

switch locale

# switch to french
msgcat::mclocale fr
msgcat::mc <label>
# switch to english
msgcat::mclocale en
msgcat::mc <label>

N.B.: Why using a default translation ?

I use tags as original text, not the default text. Thus, a default translation is necessary. Example:

tk_messageBox -message [mc errboxFatalExit]

HaO 2010-04-08: Just to put some enhancement ideas about msgcat module:

There are two use cases:

  1. Application where locale stays constant over runtime
  2. Application where locale may change over runtime

(backround: msgcat stores translations in a nested dict with the indexes locale namespace source)

Drawbacks for the use cases in the current implementation:

  1. Memory and speed optimisation possible: the in-memory translation tables may contain unneded information (Example: translation for de_ch, de and ROOT). The lookup of the locale for each translation might be avoided if the tables would be prepared for this use case.
  2. Each time the local is changed, mcload must be invoked for each message folder. This is difficult if foreign modules are used.

Possible enhancement: Possibility to switch the msgcat operation in two modes corresponding to the use cases:

  1. Do not store the locale used by mcset for each entry. Pass the msg-files in backward order (ROOT.msg de.msg de_ch.msg) to replace from down to top. Do not store any mcset data if not compatible to the current locale.
  2. mcload will load all available message files and not only those compatible to the current locale (using glob).

Drawbacks:

  1. The fact if a mcset command with a similar locale (ROOT de de_ch) is saved depends on the order of the commands. If this should be avoided, the locale must be stored. But at least any unnecessary entries might be filtered.
  2. Memory usage

API proposals

  • New command msgcat::mcmode mode ?locale? ?locale? with the following choices for mode: lazy: current and default behaviour, static : use case 1, dynamic : use case 2 - if a list of locals is appended only those locals are loaded by mcset.
  • Extend mclocale command to be able to set mode and list of locales too.

If the mode is set, one may think what to do with the current message catalogue in memory:

  • Delete it when switching from static mode to any other
  • Adopt it to the new mode (remove unwanted keys and locale information when switching to static mode)
  • Leave it as it is for all other operations

  Dynamic mode - change locale on run-time

HaO 2012-07-17: TIP 399 contains a patch to use msgcat in an environment which dynamically changes languages.

A file msgcat-1.4.5.tm is available in the linked feature request at Sourceforge . This file may be put to the tcl lib to be tested. In my experience, it is not sufficient, to have the file within the own project. It must be copied to the tcl installation beside the present file msgcat-1.4.4.tm.

At this place, there were an alternate implementation and some use instructions. Please use the upper version now and refer to the tip about the usage.

  Add notion of MC file locale to simplify mc files

I find it anoying and error-prone to repeate the locale for each mcset-command, even if it could already be known by the file name of the message catalog file.

As a consequence, one may try the extension of msgcat in the feature request 3544988 on sourceforge.

This extension basicly adds variants of the mcset and mcmset commands to use the locale given by the file name of the current sourced message cataloge file.

Here is an example file contents with the file name de.msg:

mcflset File Datei
mcflset Exit Verlassen