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 2012-07-17: TIP 399 contains a patch to use msgcat in an environment which dynamically changes languages.
A file msgcat-1.5.0.tm is available in the linked feature request #3511941 . 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.
HaO 2012-07-17: 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 (patch, package and tclapp tap-file available in the download section) (updated 2012-07-25, namespace bug).
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
The command name mcflset is an abreviation of "message catalogue with file locale set".
The mc file locale is set by the mcload command before a message file is sourced. The msgcat subcommand mcconfig is extended to get and set this locale:
% puts [mcconfig -mcfilelocale] de % mcconfig -mcfilelocale en en
The new command mcflset is identical to:
mcset [mcconfig -mcfilelocale] <src> <translation>
Old and new syntax may be mixed, for example to set local variations (this is IMHO not recommended at all, better use two message files, but I didn't find a better example):
mcflset Hello "Hallo" mcset de_CH Hello "Salü"
The set-ability of the mc file locale is not important. It might be used, to set the default value for a bunch of values within program code (and not in an msg file).
mcconfig -mcfilelocale de mcflset File Datei mcflset Exit Verlassen
One must take care, that any mcload command may set it to another value. Specially package require commands may invoke mcload commands.
HaO 2012-07-17: Given the code with a localised error message:
if {[catch {open $File r} Err]} { puts stderr [mc "File error accessing '%s': %s" $File $Err] }
and the German translation:
--de.msg-- msgcat::mcset de "File error accessing '%s': %s" "Zugriffsfehler Datei '%s': %s" --eof--
I use tags instead of a default translation. The default (english) text is contained in the root translation:
--de.msg-- msgcat::mcset de errFile "Zugriffsfehler Datei '%s': %s" --eof-- --ROOT.msg-- msgcat::mcset {} errFile "File error accessing '%s': %s" --eof-- if {[catch {open $File r} Err]} { puts stderr [mc errFile $File $Err] }
Why that ?
HaO 2012-07-24: To use a newer msgcat Version, it is to my experience not sufficient to have a new package in a custom auto_path. There is always the original found, I don't know why. A new package must be set to the default location.
Thus the new msgcat.tcl is renamed to msgcat-1.x.x.tm (1.x.x: version greater 1.4.5 which will be the version in tcl 8.5.12) and saved to:
If the program is wrapped to an executable starkit (not .kit), one may save it to:
If an application is wrapped using ActiveState TclApp, I did not found any way to wrap anything to the upper path. But I made a custom tap file containing a pckIndex.tcl and a msgcat.tcl and this worked (at least for a console application). The tap-file for msgcat-1.5.1 is here: msgcat-1.5.1.zip
HaO 2012-08-22: AK asked by private mail:
Do we have a <<LocaleChanged>> virtual event like we have <<ThemeChanged>>, which is used to inform all widgets when 'mclocale' was switched at runtime ?
HaO answered:
No, we dont have this currently.
As it is a tcl-only package, we do not have the bind command.
Thus we could register a command which is called when the locale changes:
msgcat::mcconfig -command ?lcmd?
When the command failes, bgerror is called. An eventual locale change command (ex: msgcat::mclocale en_us), which executes the commands does not return with an error if a locale change callback fails.
Example:
package provide mymodule 1.0 namespace eval mymodule { # Register a locale change callback msgcat::mcconfig -command [list myLocaleChanged] ... # Unregister the locale change callback msgcat::mcconfig -command "" }