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 [http://groups.yahoo.com/group/tcl_announce/message/1750]) 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 ====== <> ---- <> Dynamic mode - change locale on run-time (TIP399) [HaO] 2012-07-17: [http://www.tcl.tk/cgi-bin/tct/tip/399.html%|%TIP 399%|%] contains a patch to use msgcat in an environment which dynamically changes languages. A file [https://sourceforge.net/tracker/download.php?group_id=10894&atid=360894&file_id=449122&aid=3511941%|%msgcat-1.5.0.tm%|%] is available in the linked feature request [https://sourceforge.net/tracker/?func=detail&aid=3511941&group_id=10894&atid=360894%|%#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`. * At this place, there were an alternate implementation and some use instructions. These are superseeded by the upper information. * This feature is also included in the download files of [https://sourceforge.net/tracker/?func=detail&aid=3544988&group_id=10894&atid=360894%|%#3544988%|%]. There is also a tclapp `tap`-file available as download. '''[HaO] 2012-08-27:''' Two things happened: * [AK] has asked how other packages may ask for information about a locale change (see below '''Dynamic namespace change callback'''). * TIP 399 was voted yes. [DGP] voted present with the following comment: What I would prefer is to vote YES for the "turn the whole package over to Harald Oehlmann to do as he pleases". The proposal seems fine, to address the problem posed. What gives me pause is that the TIP seems to demonstrate that the original design of msgcat just isn't any good. At some point we'd be better off not slapping in more bells and whistles and alternatives and just creating a new (version of a?) package that learns the lessons and gets it right this time. ***Complete solution*** I came to the conclusion, that dynamic local change is wanted but the proposed solution only solves parts of the issue. Here is an extract of my message on the core-list: ---- Unfortunately, the solution within the tip is half-baken and I ask for some time to design a better solution and rewrite a tip. I am sorry for that but I am convinced, this is the best way to go. I might be wrong, but at least I will try. A good solution for TIP 399 must automatically '''reload''' locale files on a locale change. ***Sketch of my current view of a solution*** There is a new command to set per caller namespace config data (namespace equal package, as each package should have one namespace and one set of locale files): ====== msgcat::mcpackageconfig ?-namespace namespace? setting ?value? ====== Settings per caller namespace/package: * message file folder (also auto-set by msgcat::mcload) (to be able to load missing locale files on a locale change) * callback function before reload of the message file due to a locale change (change to a jet unloaded locale) * callback function after a locale change * flag, if locale files should be reloaded if needed All of them are get and setable. The function returns with an error, if the namespace does not exist. The advantages of this: * the concept of the caller/package namespace already exists within msgcat. This is continued. * the caller namespace may be autodetected or specified * the settings might automatically be cleared if the namespace is removed and the corresponding function may be automatically disabled * IMHO very transparent There are the following additional configuration settings: * currently loaded locales (sum of all mcpreferences, readonly) * Flag, if unneeded locale data is cleared on locale change <> <> Dynamic namespace change callback (TIP399 related) [HaO] 2012-08-22: [AK] asked by private mail: Do we have a '''<>''' virtual event like we have '''<>''', 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? ====== * '''lcmd''' : list of cmd ?namespace? * '''cmd''': Command to call when locale changes. Specify empty string to unregister. * '''namespace''': the callers module namespace which is only used as a register id to store the command. If not specified, the callers current namespace is used. There is one registered command possible per namespace value. When the command fails, 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 "" } ====== [AK] 2012-08-22 by E-Mail: > As it is a tcl-only package, we do not have the bind command. True. Nor the 'event generate'. I had thought about auto-detecting a Tk environment to restrict when it broadcasts a change, however your idea with a configurable callback is better, from an architectural point of view. Hm. ... Hadn't thought about multiple callbacks. Guess because I was thinking in terms of events, where I can bind multiple things as I see fit. This restriction to one-per-namespace, and providing it through a list ... I do not like that too much. It is workable, true. Still don't like it. This shoehorning multiple callbacks through a single config option feels wrong. For multiple callbacks I would use dedicated (un)register commands, and tokens. I.e. ====== msgcat::register ====== returns a token, which is then the argument to ====== msgcat::unregister ====== to identify the callbacks and remove them individually. See http://docs.activestate.com/activetcl/8.5/tcllib/uev/uevent.html for an example of how I did that for a tcl event package. [WHD] 2012-08-22 by E-Mail: See also the hook module in Tcllib. [HaO] 2012-08-27: Discussion continues in the upper point '''Dynamic mode - change locale on run-time'''. There I write, why I prefer namespace instead of tolkens. ---- [MG] 2012-08-22: I use something similar to this in his app: ====== proc setLocale {new_locale} { variable locales; variable current_locale; set split [split $new_locale "_"] set preflist [list] for {set i 0} {$i < [llength $split]} {incr i} { lappend preflist [join [lrange $split 0 end-$i] "_"] } set current_locale "" foreach x $preflist { if { [info exists locales($x)] } { set current_locale $x break; } } if { ![info exists current_locale] || $current_locale eq "" } { set current_locale "en_gb" } # Set our best available ::msgcat::mclocale $current_locale # Update display to make sure we're using it if { $skin ne "" } { ::skin::${skin}::locale } setUpMenu setAppTitle return; };# setLocale ====== The $locales array records exactly which locales I've loaded some form of translation for, since msgcat doesn't seem to expose that information. The code makes sure that there actually is a translation for the requested locale, and picks a less specific one if necessary in much the same way msgcat does. It falls back on en_gb as a default. Like msgcat, all the locale names are stored entirely in lowercase (en_gb not en_GB). The code after the last comment calls various procs which alter existing GUI elements to use the new locale, but could easily be replaced with something like ====== proc rchildren {widget} { event generate $widget <> foreach x [winfo children $widget] { rchildren $x } } rchildren . ====== so you could bind to <> for the assorted widgets instead. [HaO] 2012-08-27: Thank you, Mike, for the contribution. The language change is user level and should still work as you do it, but this is slightly off-topic. Andreas is asking, how non-user packages which store translated messages somehow (like the tcllib tooltip package) may by their action be informed about a locale change. <> <> Dynamic Locale Change for msgcat with on-demand File Load [HaO] 2012-09-06: As the solution of TIP399 was half baken, here is a new proposal. See feature request [https://sourceforge.net/tracker/?func=detail&aid=3565279&group_id=10894&atid=360894] containing msgcat 1.6 and a prepared TIP for review. **Features** ***Automatic message file load on locale change*** ====== % msgcat::mclocale en en % namespace eval p1 { msgcat::mcload msgs } ... will load message files en.msg and ROOT.msg from folder msgs ... % msgcat::mclocale fr ...will load fr.msg from folder msgs and locale will be available ====== ***Locale change callback*** A package may inform itself about locale change: ====== % namespace eval p1 {msgcat::mcpackageconfig changecmd updateGUI} % msgcat::mclocale de ...will load de.msg from folder msgs and locale will be available ...will invoke "::pi::updateGUI de {}" ====== ***Other catalog sources*** Using a load callback, catalog data may be fetched from other sources like a data base instead/in addition to message files: ====== namespace eval db { msgcat::mcpackageconfig loadcmd loadMessages msgcat::mcconfig loadedpackages\ [concat [msgcat::mcconfig loadedpackages] [namespace current]] proc loadMessages args { foreach locale $args { if {[LocaleInDB $locale]} { msgcat::mcmset $locale [GetLocaleList $locale] } } } } ====== Refer to the tip below for details. <> <> Draft TIP399BIS: Dynamic Locale Changing for msgcat with on-demand File Load ======none TIP: 399BIS Title: Dynamic Locale Changing for msgcat with on-demand File Load Version: $Revision: 1.0 $ Author: Harald Oehlmann State: Draft Type: Project Vote: Done Created: 06-Sep-2012 Post-History: Keywords: Tcl,localization,msgcat Tcl-Version: 8.6 ====== **Abstract** This TIP adds dynamic locale switching capabilities to the '''msgcat''' package. **Rationale** Within a multi-language application like a web-server, one may change the locale quite frequently, for example if users with different locales are requesting pages. Unfortunately, this does not fit well with the model adopted by the '''msgcat''' package, which assumes that all code follows this sequence: 1. Set locale list: '''mclocale''' ''locale'' 2. Load language files with other package load: '''mcload''' ''msg-folder'' 3. Translate strings: '''mc''' ''key args...'' Note that if the locale should be changed after other packages are loaded, one must restart at step 2. This requires reloading all packages which is mostly not practical. The aim of this tip is to extend the package by dynamic locale change capabilities. msgcat will reload any missing message catalog files of all currently loaded packages on a locale change. This tip compares to tip399 that the package is able to load message catalog files on demand, e.g. specially on a locale change. **Specification** ***Package equals client namespace*** A '''client package''' is a package which uses msgcat. A unique namespace is required for each client package. Within msgcat, namespace and package is always connected. Up to now, the msgcat package used this namespace as an identifier to store the catalog data of a certain package. This is now extended to additional properties which are stored for a package. ***msgcat state*** msgcat stores message catalog data in dependency of the locale, the package and the key (see '''mcset''' command). The msgcat package maintains two new state lists: * loadedlocales: list of currently loaded locals * loadedpackages: list of currently loaded packages. The message catalog data always corresponds to these lists. The listed locals and packages are currently present. Those lists may be get or set by the new command '''mcconfig'''. They may also be changed my '''mcload''' or '''mclocale'''. A new option '''removeobsoletelocale''' controls, if any currently unneded locale data is discarded. * If set, '''loadedlocales''' is always set erqual to '''mcpreferences'''. This may add or remove items on the '''loadedlocales''' list. * If not set, '''loadedlocales''' may only be extended by a locale change ('''mclocale locale'''). Those options are exposed by the following new command: > '''msgcat::mcconfig option''' ?''value''? where option is one of the above options '''loadedlocales''', '''loadedpackages''' or '''removeobsoletelocale'''. The initial default values are emty lists and false. An option may be read by not specifying a value. If a value is given, the option is set. Setting those options may lead to deletion or loading of message catalog data as described in the two chapers below '''loadedlocales change action''' and '''loadedpackages change action'''. ***package state*** msgcat maintains 3 options per client package. Those options may be get or set using: > '''msgcat::mcpackageconfig ?-package namespace? option ?value? The optional argument '''-package''' specifies the client package namespace of the option. If it is not given, the caller namespace is used. This package must not be included in the list '''loadedpackages'''. The namespace must not exist. Available options are: * mcfolder: folder of the message files of the package * loadcmd: a callback before any package message files are loaded * changecmd: callback if the locale is changed The options are cleared if set to the empty string. ****package option mcfolder (and mcload)**** This is the message folder of the package. On locale change, message files may be reloaded on the following conditions: * the package is listed in '''loadedpackages''' * the package namespace exists * this option is set to a folder Setting this value is identical to an '''mcload''' in the given namespace and performs the following actions: * if already in '''loadedpackages''' and same '''mcfolder''' specified: return with 0 * if already in '''loadedpackages''', '''mcfolder''' changed and '''removeobsoletelocale''' active, clear the current package data * if not in '''loadedpackages''', append it * set property '''mcfolder''' * do the '''MC package list changed action''' below * If called as mcload, return number of loaded message files ****package option loadcmd**** This callback is invoked before a set of message catalog files are loaded for the package which has this property set. This callback may be used to do any preparation work for message file load or to get the message data from another source like a data base. In this case, no message files are used. See chapter '''callback invokation''' below. The paramer list appended to this callback is the list of locales to load. ****package option changecmd**** This callback is invoked when a local change was performed. Its purpose is to allow a package to update a gui. Tk may be extended to register to this callback and to invoke a virtual event. See chapter '''callback invokation''' below. The paramer list appended to this callback is '''mcpreferences'''. All registered packages are invoked in no particular order. ***callback invokation*** There are two callbacks as described above, packages may register to. Callbacks are invoked under the following conditions: * the registration namespace exists The callback is invoked in the registered namespace with a set of locales as parameters as follows: > namespace inscope $ns $callback {*}$loclist Any error within the callback stops the operation which invoked the callback. This might be surprising, as the error might be in another package. ~~ loadedpackages change action The list of loaded packages may change in the following circumstances: * '''msgcat::mcload''' invokation adds the invocating package, if it is not already on the list. * Setting '''mcfolder''' using '''msgcat::mcconfig''' has the same effect as '''msgcat::mcload''' * '''msgcat::mcpackageconfig''' may manipulate the list directly The following action is done on a list change: * check if the namespaces of all members on the new '''loadedpackages''' list exist. Remove any unexisting members. * remove all message catalog entries which belong to packages not any more on the list. * for each new package, append it to the list and start the catalog load action (see below) with '''mcpreferences''' as set of locales to load. ***loadedlocales change action*** The list of loaded locales may change in the following circumstances: * '''msgcat::mclocale''' sets the list to '''mcpreferences''' if '''removeobsoletelocale''' true. Otherwise, it appends any item in '''mcpreferences''' not currently on the list. * '''msgcat::mcpackageconfig''' may manipulate the list directly The following action is done on a list change: * Remove any member not present any more in the new list. * remove all message catalog entries which belong to removed locales. * build a list of locales which are new on the list and append it to the list. * For all packages on '''loadedpackages''', invoke the catalog load action (see below) with the list of new locales. ***catalog load action*** The following steps are performed when message catalog files should be loaded: * Invoke the callback '''loadcmd''' if registered for the package. * If the package property '''mcfolder''' is not set, return. * for each locale to load, build the message catalog path and source the message file if it exists. * on any file error, the invoking command returns with a script error. This might be surprising, as it may not be in the invoking package. * the message file may itself load packages which may use msgcat as another package namespace. **Example Usage** ***Example from tip399*** Imagine an application which supports the current user language and French, German and English. An external package '''tp''' is used. The package uses '''msgcat''' and performes within the '''package require tp''' call: ====== package require msgcat msgcat::mcload [file join [file dirname [info script]] msgs] ====== An implementation of the application with the current msgcat 1.4.4 would require the following initialisation sequence: ====== package require msgcat package require np ====== and the following code to change the locale to French: ====== package forget np msgcat::mclocale fr package require np ====== Using the extension of this tip, one may load as usual: ====== package require msgcat package require np ====== and to change to french locale: ====== msgcat::mclocale fr ====== The first time, a locale is required, all corresponding message files of all packages which use msgcat get loaded. This might be a heavy operation. If a locale is reactivated (and the message catalog data was not cleared), it is a quick operation. Without this tip, it is computational expensive (if possible, as many packages are not reloadable or a reload may disturb current processing, e.g., by forcing the closing of sockets, etc.). ***Change with no need to come back*** If it is shure, that a locale is changed and the then obsolete data is of no use, one may activate its removal: ====== msgcat::mclocale fr msgcat::mcconfig removeobsoletelocale 1 ====== or ====== msgcat::mcconfig removeobsoletelocale 1 msgcat::mclocale fr ====== ***Use a callback to be notified about a locale change*** Packages which display a gui may update their widgets when the locale changes. To register to a callback, use: ====== namespace eval gui { msgcat::mcpackageconfig changecmd updateGUI proc updateGui args { puts "New locale is '[lindex $args 0]'." } } % msgcat::mclocale fr fr % New locale is 'fr'. ====== ***To use another locale source than message catalog files*** If locales (or additional locales) are contained in another source like a data base, a package may use the load callback and not ''mcload'': ====== namespace eval db { msgcat::mcpackageconfig loadcmd loadMessages msgcat::mcconfig loadedpackages\ [concat [msgcat::mcconfig loadedpackages] [namespace current]] proc loadMessages args { foreach locale $args { if {[LocaleInDB $locale]} { msgcat::mcmset $locale [GetLocaleList $locale] } } } } ====== **Reference Implementation** See Tcl Feature Request [http://sourceforge.net/tracker/?func=detail&aid=3565279&group_id=10894&atid=360894%|%360894], **Compatibility** Imagined incompatibilities: * If packages call '''mcload''' multiple times with different folders, the data was currently appended. This is still the case, but only the last folder is used for any reload. The property '''mcfolder''' may be transformed to a list to cover this case. * The return value of '''mcload''' (file count) may be much higher as there may be loaded much more files. I suppose, this value is only used by the test suite to verify functionality and is not for big general use. * Message files may not be aware, that they may be loaded at any moment and not only after their own '''mcload'''. I suppose, this is the biggest issue but I think, there is no alternative. * Message files do not get reloaded any more, if a second '''mcload''' is issued with the same path argument. **Issues** Imagined issues: * Packages might not be aware of a locale change and may buffer translations outside of '''msgcat'''. Packages should not buffer msgcat messages if they are used in a dynamic locale application (like tklib tooltip does for example). * The clock command currently has a small dynamic patch for msgcat implemented. This may be removed in favour to new msgcat features. But there is quite an impact, as a '''clock -locale''' issues a '''msgcat::mclocale''' with all its new consequences. We could have a '''locale list per package''' and a '''locale per package''' to prevent this issue but this seams to aim bejond the aim. Another possibility would be, that the clock package would use an own mechanism (and not msgcat) which would be my favorite if there are issues. **Extensions** * The proposed interface to manipulate the list of packages is quite basic. Additional commands like '''mcaddpackage''' and specially '''mcclearpackage''' may be handy and easy to implement. * The proposed interfaces to '''mcconfig''' and '''mcpackageconfig''' (compared to tip399) allow only to set one option at a time. This might be changed but is IMHO only for little use. The dashes in front of the options were also removed. **Alternatives** The alternative is the former TIP399. This will IMHO not work, as the list of locales must be known before any package load. If the easy of this patch is once experienced, nobody would accept the burden. **Copyright** This document has been placed in the public domain. <> <> New implementation and TIP After around 5 implementations of the feature and a deep look to the (IMHO complex) clock code, there is a new [http://core.tcl.tk/tcl/info/d0f6a51a8f%|%reference implementation%|%] and TIP (just sent to the core list, must be soon in the [http://code.activestate.com/lists/tcl-core/%|%archives%|%]): <> ---- <> Add notion of MC file locale to simplify mc files (TIP404) [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 [https://sourceforge.net/tracker/?func=detail&aid=3544988&group_id=10894&atid=360894%|%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. ***Example message 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 "'''m'''essage '''c'''atalogue with '''f'''ile '''l'''ocale '''set'''". ***Set and get mc file locale*** 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] ====== 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ü" ====== ***Setting mc file locale by command*** 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. ---- * 2012-08-22: TIP 404 was voted yes [http://code.activestate.com/lists/tcl-core/11788/] * 2012-08-28: [DKF] started an implementation branch [https://core.tcl.tk/tcl/timeline?r=tip-404] * 2012-08-29: Discussion on the core list, if the command '''mcconfig''' should be removed and just the automatic '''mcflset''' would be implemented. I am in favor of this. * 2012-09-07: Version IMHO ready for merge: [http://core.tcl.tk/tcl/info/7236bac9ae] <> ---- <> Use tags instead of text [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 ? * If I change the default text, I do not have to change the translation keys * It feels more systematic to me to separate text and code * If a text is the same in english but different in german, I may not make any difference * If I forget a translation, I get only a stupid tag. Nothing for lazy guys... <> ---- <> Exchange package msgcat by a custom version [HaO] 2012-07-24: The clock command explicitly requires msgcat 1.4. An alternate `msgcat` version must also be in the default path, as the clock package is loaded before any script may extend the `auto_path`. Thus the new `msgcat.tcl` is renamed to `msgcat-1.x.x.tm` (1.x.x: version greater 1.4.5 which is the version in tcl 8.5.12) and saved to: * `/lib/lib8/8.5` If the program is wrapped to an executable starkit (not .kit), one may save it to: * `.vfs/lib/lib8/8.5` 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: [https://sourceforge.net/tracker/download.php?group_id=10894&atid=360894&file_id=449764&aid=3544988%|%msgcat-1.5.1.zip%|%] <> ---- **Examples of using `msgcat`** * [simple text editor] * [HiLo-international] * [multilingual menu] * [Tk internationalization] **See also** * [msgcat magic] * [msgcat and shortcut keys] * [msgcat-Ready Script Utility] * [msgcat-x] * [ampersand magic] * [locale] * [localization] * [message catalog] * [Tk and msgcat] <> Tcl syntax help | Arts and crafts of Tcl-Tk programming | Command | Local | String Processing | Package