diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | doc/msgcat.n | 83 | ||||
-rw-r--r-- | library/msgcat/msgcat.tcl | 191 | ||||
-rw-r--r-- | library/msgcat/pkgIndex.tcl | 2 | ||||
-rw-r--r-- | tests/msgcat.test | 883 |
5 files changed, 692 insertions, 480 deletions
@@ -1,3 +1,16 @@ +2002-06-17 Don Porter <dgp@users.sourceforge.net> + + * doc/msgcat.n: + * library/msgcat/msgcat.tcl: + * library/msgcat/pkgIndex.tcl: + * tests/msgcat.test: Revised locale initialization to interpret + environment variable locale values according to XPG4, and to + recognize the LC_ALL and LC_MESSAGES values over that of LANG. + Also added many Windows Registry locale values to those + recognized by msgcat. Revised tests and docs. Bumped to + version 1.3. Thanks to Bruno Haible for the report and + assistance crafting the solution. [Bug 525522, 525525] + 2002-06-16 Miguel Sofer <msofer@users.sourceforge.net> * generic/tclCompile.c (TclCompileTokens): a better algorithm for diff --git a/doc/msgcat.n b/doc/msgcat.n index dddf499..2fb5591 100644 --- a/doc/msgcat.n +++ b/doc/msgcat.n @@ -15,7 +15,7 @@ msgcat \- Tcl message catalog .SH SYNOPSIS \fBpackage require Tcl 8.2\fR .sp -\fBpackage require msgcat 1.2\fR +\fBpackage require msgcat 1.3\fR .sp \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? .sp @@ -80,37 +80,46 @@ fixed width (which will be the width of the widest button). \fB::msgcat::mclocale \fR?\fInewLocale\fR? This function sets the locale to \fInewLocale\fR. If \fInewLocale\fR is omitted, the current locale is returned, otherwise the current locale -is set to \fInewLocale\fR. -The initial locale defaults to the locale specified in -the user's environment. See \fBLOCALE AND SUBLOCALE SPECIFICATION\fR +is set to \fInewLocale\fR. msgcat stores and compares the locale in a +case-insensitive manner, and returns locales in lowercase. +The initial locale is determined by the locale specified in +the user's environment. See \fBLOCALE SPECIFICATION\fR below for a description of the locale string format. .TP \fB::msgcat::mcpreferences\fR Returns an ordered list of the locales preferred by the user, based on the user's language specification. The list is ordered from most specific to least -preference. If the user has specified LANG=en_US_funky, -this procedure would return {en_US_funky en_US en}. +preference. The list is derived from the current +locale set in msgcat by \fBmsgcat::mclocale\fR, and +cannot be set independently. For example, if the +current locale is en_US_funky, then \fBmsgcat::mcpreferences\fR +returns {en_US_funky en_US en}. .TP \fB::msgcat::mcload \fIdirname\fR Searches the specified directory for files that match -the language specifications returned by \fB::msgcat::mcpreferences\fR. -Each file located is sourced. The file extension is ``.msg''. -The number of message files which matched the specification +the language specifications returned by \fB::msgcat::mcpreferences\fR, +extended by the file extension ``.msg''. Each matching file is +read in order, assuming a UTF-8 encoding. The file contents are +then evaluated as a Tcl script. This means that non-Latin characters +may be present in the message file either directly in their UTF-8 +encoded form, or by use of the backslash-u quoting recognized by Tcl +evaluation. The number of message files which matched the specification and were loaded is returned. .TP \fB::msgcat::mcset \fIlocale src-string \fR?\fItranslate-string\fR? Sets the translation for \fIsrc-string\fR to \fItranslate-string\fR -in the specified \fIlocale\fR. If \fItranslate-string\fR is not -specified, \fIsrc-string\fR is used for both. The function -returns \fItranslate-string\fR. +in the specified \fIlocale\fR and the current namespace. If +\fItranslate-string\fR is not specified, \fIsrc-string\fR is used +for both. The function returns \fItranslate-string\fR. .TP \fB::msgcat::mcmset \fIlocale src-trans-list\fR Sets the translation for multiple source strings in -\fIsrc-trans-list\fR in the specified \fIlocale\fR. +\fIsrc-trans-list\fR in the specified \fIlocale\fR and the current +namespace. \fIsrc-trans-list\fR must have an even number of elements and is in the form {\fIsrc-string translate-string\fR ?\fIsrc-string -translate-string ...\fR?} \fBmcsetcat::mcmset\fR can be significantly +translate-string ...\fR?} \fBmsgcat::mcmset\fR can be significantly faster than multiple invocations of \fBmsgcat::mcset\fR. The function returns the number of translations set. .TP @@ -125,22 +134,35 @@ same stack context as the call to \fB::msgcat::mc\fR. The return vaue of \fB::msgcat::mcunknown\fR is used as the return vaue for the call to \fB::msgcat::mc\fR. -.SH "LOCALE AND SUBLOCALE SPECIFICATION" +.SH "LOCALE SPECIFICATION" .PP -The locale is specified by a locale string. +The locale is specified to \fBmsgcat\fR by a locale string +passed to \fB::msgcat::mclocale\fR. The locale string consists of a language code, an optional country code, and an optional system-specific code, each separated by ``_''. The country and language codes are specified in standards ISO-639 and ISO-3166. -For example, the locale ``en'' specifies English and - ``en_US'' specifes U.S. English. +For example, the locale ``en'' specifies English and ``en_US'' specifies +U.S. English. .PP -The locale defaults to the value in \fBenv(LANG)\fR at the time the -\fBmsgcat\fR package is loaded. On Windows, if \fBenv(LANG)\fR is not -set, the package will attempt to extract locale information from the -registry. If it cannot find this information in the registry, or on -non-Windows platforms when \fBenv(LANG)\fR is not defined, the -locale defaults to ``C''. +When the msgcat package is first loaded, the locale is initialized +according to the user's environment. The variables \fBenv(LC_ALL)\fR, +\fBenv(LC_MESSAGES)\fR, and \fBenv(LANG)\fR are examined in order. +The first of them to have a non-empty value is used to determine the +initial locale. The value is parsed according to the XPG4 pattern +.CS +language[_country][.codeset][@modifier] +.CE +to extract its parts. The initial locale is then set by calling +\fBmsgcat::mclocale\fR with the argument +.CS +language[_country][_modifier] +.CE +On Windows, if none of those environment variables is set, msgcat will +attempt to extract locale information from the +registry. If all these attempts to discover an initial locale +from the user's environment fail, msgcat defaults to an initial +locale of ``C''. .PP When a locale is specified by the user, a ``best match'' search is performed during string translation. For example, if a user specifies @@ -177,7 +199,7 @@ then the parent of the current namespace, and so on until the global namespace is reached. This allows child namespaces to "inherit" messages from their parent namespace. .PP -For example, executing the code +For example, executing (in the ``en'' locale) the code .CS mcset en m1 ":: message1" mcset en m2 ":: message2" @@ -214,10 +236,15 @@ es.msg -- spanish en_UK.msg -- UK English .CE .IP [3] -The file contains a series of calls to mcset, setting the -necessary translation strings for the language. For example: +The file contains a series of calls to \fBmcset\fR and +\fBmcmset\fR, setting the necessary translation strings +for the language, likely enclosed in a \fBnamespace eval\fR +so that all source strings are tied to the namespace of +the package. For example, a short \fBes.msg\fR might contain: .CS -::msgcat::mcset es "Free Beer!" "Cerveza Gracias!" +namespace eval ::mypackage { + ::msgcat::mcset es "Free Beer!" "Cerveza Gracias!" +} .CE .SH "RECOMMENDED MESSAGE SETUP FOR PACKAGES" diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index 7299004..01b4477 100644 --- a/library/msgcat/msgcat.tcl +++ b/library/msgcat/msgcat.tcl @@ -10,25 +10,41 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: msgcat.tcl,v 1.13 2002/04/20 00:35:19 dgp Exp $ +# RCS: @(#) $Id: msgcat.tcl,v 1.14 2002/06/17 05:37:39 dgp Exp $ package require Tcl 8.2 -package provide msgcat 1.2.3 +package provide msgcat 1.3 namespace eval msgcat { namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \ mcunknown # Records the current locale as passed to mclocale - variable locale "" + variable Locale "" # Records the list of locales to search - variable loclist {} + variable Loclist {} # Records the mapping between source strings and translated strings. The # array key is of the form "<locale>,<namespace>,<src>" and the value is # the translated string. - array set msgs {} + array set Msgs {} + + # Map of language codes used in Windows registry to those of ISO-639 + array set WinRegToISO639 { + 0409 en_US 0809 en_UK 43c gd 83c ga 01 ar 02 bg 03 ca 04 zh 05 + cs 06 da 07 de 08 el 0a es 0b fi 0c fr 0d he 0e hu 0f is 10 it + 11 ja 12 ko 13 da 14 no 15 pl 16 pt 17 rm 18 ro 19 ru 1a hr + 1b sk 1c sq 1d sv 1e th 1f tr 20 ur 21 id 22 uk 23 be 24 sl + 25 et 26 lv 27 lt 28 tg 29 fa 2a vi 2b hy 2c az 2d eu 2e wen + 2f mk 30 bnt 31 ts 33 ven 34 xh 35 zu 36 af 37 ka 38 fo 39 hi + 3a mt 3b se 3d yi 3e ms 3f kk 40 ky 41 sw 42 tk 43 uz 44 tt + 45 bn 46 pa 47 gu 48 or 49 ta 4a te 4b kn 4c ml 4d as 4e mr + 4f sa 50 mn 51 bo 52 cy 53 km 54 lo 55 my 56 gl 57 kok 58 mni + 59 sd 5a syr 5b si 5c chr 5d iu 5e am 5f ber 60 ks 61 ne 62 fy + 63 ps 64 tl 65 div 66 bin 67 ful 68 ha 69 nic 6a yo 70 ibo + 71 kau 72 om 73 ti 74 gn 75 cpe 76 la 77 so 78 sit 79 pap + } } # msgcat::mc -- @@ -51,20 +67,20 @@ proc msgcat::mc {src args} { # Check for the src in each namespace starting from the local and # ending in the global. - variable msgs - variable loclist - variable locale + variable Msgs + variable Loclist + variable Locale set ns [uplevel 1 [list ::namespace current]] while {$ns != ""} { - foreach loc $loclist { - if {[info exists msgs($loc,$ns,$src)]} { + foreach loc $Loclist { + if {[info exists Msgs($loc,$ns,$src)]} { if {[llength $args] == 0} { - return $msgs($loc,$ns,$src) + return $Msgs($loc,$ns,$src) } else { return [uplevel 1 \ - [linsert $args 0 ::format $msgs($loc,$ns,$src)]] + [linsert $args 0 ::format $Msgs($loc,$ns,$src)]] } } } @@ -72,7 +88,7 @@ proc msgcat::mc {src args} { } # we have not found the translation return [uplevel 1 \ - [linsert $args 0 [::namespace origin mcunknown] $locale $src]] + [linsert $args 0 [::namespace origin mcunknown] $Locale $src]] } # msgcat::mclocale -- @@ -88,8 +104,8 @@ proc msgcat::mc {src args} { # Returns the current locale. proc msgcat::mclocale {args} { - variable loclist - variable locale + variable Loclist + variable Locale set len [llength $args] if {$len > 1} { @@ -97,15 +113,15 @@ proc msgcat::mclocale {args} { } if {$len == 1} { - set locale [string tolower [lindex $args 0]] - set loclist {} + set Locale [string tolower [lindex $args 0]] + set Loclist {} set word "" - foreach part [split $locale _] { + foreach part [split $Locale _] { set word [string trimleft "${word}_${part}" _] - set loclist [linsert $loclist 0 $word] + set Loclist [linsert $Loclist 0 $word] } } - return $locale + return $Locale } # msgcat::mcpreferences -- @@ -120,8 +136,8 @@ proc msgcat::mclocale {args} { # Returns an ordered list of the locales preferred by the user. proc msgcat::mcpreferences {} { - variable loclist - return $loclist + variable Loclist + return $Loclist } # msgcat::mcload -- @@ -164,14 +180,14 @@ proc msgcat::mcload {langdir} { # Returns the new locale. proc msgcat::mcset {locale src {dest ""}} { - variable msgs + variable Msgs if {[string equal $dest ""]} { set dest $src } set ns [uplevel 1 [list ::namespace current]] - set msgs([string tolower $locale],$ns,$src) $dest + set Msgs([string tolower $locale],$ns,$src) $dest return $dest } @@ -187,7 +203,7 @@ proc msgcat::mcset {locale src {dest ""}} { # Returns the number of pairs processed proc msgcat::mcmset {locale pairs } { - variable msgs + variable Msgs set length [llength $pairs] if {$length % 2} { @@ -198,7 +214,7 @@ proc msgcat::mcmset {locale pairs } { set ns [uplevel 1 [list ::namespace current]] foreach {src dest} $pairs { - set msgs($locale,$ns,$src) $dest + set Msgs($locale,$ns,$src) $dest } return $length @@ -252,61 +268,76 @@ proc msgcat::mcmax {args} { return $max } -# Initialize the default locale +# Convert the locale values stored in environment variables to a form +# suitable for passing to [mclocale] +proc msgcat::ConvertLocale {value} { + # Assume $value is of form: $language[_$territory][.$codeset][@modifier] + # Convert to form: $language[_$territory][_$modifier] + # + # Comment out expanded RE version -- bugs alleged + #regexp -expanded { + # ^ # Match all the way to the beginning + # ([^_.@]*) # Match "lanugage"; ends with _, ., or @ + # (_([^.@]*))? # Match (optional) "territory"; starts with _ + # ([.]([^@]*))? # Match (optional) "codeset"; starts with . + # (@(.*))? # Match (optional) "modifier"; starts with @ + # $ # Match all the way to the end + #} $value -> language _ territory _ codeset _ modifier + regexp {^([^_.@]*)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \ + -> language _ territory _ codeset _ modifier + set ret $language + if {[string length $territory]} { + append ret _$territory + } + if {[string length $modifier]} { + append ret _$modifier + } + return $ret +} -namespace eval msgcat { +# Initialize the default locale +proc msgcat::Init {} { + # # set default locale, try to get from environment - if {[info exists ::env(LANG)]} { - mclocale $::env(LANG) - } else { - if { $tcl_platform(platform) == "windows" } { - # try to set locale depending on registry settings - # - set key {HKEY_CURRENT_USER\Control Panel\International} - if {[catch {package require registry}] || \ - [catch {registry get $key "locale"} locale]} { - mclocale "C" - } else { - - # - # Clean up registry value for translating LCID value - # by using only the last 2 digits, since first - # 2 digits appear to be the country... For example - # 0409 - English - United States - # 0809 - English - United Kingdom - # - set locale [string trimleft $locale "0"] - set locale [string range $locale end-1 end] - set locale [string tolower $locale] - switch -- $locale { - 01 { mclocale "ar" } - 02 { mclocale "bg" } - 03 { mclocale "ca" } - 04 { mclocale "zh" } - 05 { mclocale "cs" } - 06 { mclocale "da" } - 07 { mclocale "de" } - 08 { mclocale "el" } - 09 { mclocale "en" } - 0a { mclocale "es" } - 0b { mclocale "fi" } - 0c { mclocale "fr" } - 0d { mclocale "he" } - 0e { mclocale "hu" } - 0f { mclocale "is" } - 10 { mclocale "it" } - 11 { mclocale "ja" } - 12 { mclocale "ko" } - 13 { mclocale "da" } - 14 { mclocale "no" } - 15 { mclocale "pl" } - 16 { mclocale "pt" } - - default { mclocale "C" } - } - } - } else { - mclocale "C" - } + # + foreach varName {LC_ALL LC_MESSAGES LANG} { + if {[info exists ::env($varName)] + && ![string equal "" $::env($varName)]} { + mclocale [ConvertLocale $::env($varName)] + return + } + } + # + # On Windows, try to set locale depending on registry settings, + # or fall back on locale of "C". Other platforms will return + # when they fail to load the registry package. + # + set key {HKEY_CURRENT_USER\Control Panel\International} + if {[catch {package require registry}] \ + || [catch {registry get $key "locale"} locale]} { + mclocale "C" + return + } + # + # Keep trying to match against smaller and smaller suffixes + # of the registry value, since the latter hexadigits appear + # to determine general language and earlier hexadigits determine + # more precise information, such as territory. For example, + # 0409 - English - United States + # 0809 - English - United Kingdom + # Add more translations to the WinRegToISO639 array above. + # + variable WinRegToISO639 + set locale [string tolower $locale] + while {[string length $locale]} { + if {![catch {mclocale $WinRegToISO639($locale)}]} { + return + } + set locale [string range $locale 1 end] } + # + # No translation known. Fall back on "C" locale + # + mclocale C } +msgcat::Init diff --git a/library/msgcat/pkgIndex.tcl b/library/msgcat/pkgIndex.tcl index cc1af0c..9d16a19 100644 --- a/library/msgcat/pkgIndex.tcl +++ b/library/msgcat/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.2]} {return} -package ifneeded msgcat 1.2.3 [list source [file join $dir msgcat.tcl]] +package ifneeded msgcat 1.3 [list source [file join $dir msgcat.tcl]] diff --git a/tests/msgcat.test b/tests/msgcat.test index 633c869..2ea01cd 100644 --- a/tests/msgcat.test +++ b/tests/msgcat.test @@ -1,330 +1,457 @@ -# Commands covered: ::msgcat::mc ::msgcat::mclocale -# ::msgcat::mcpreferences ::msgcat::mcload -# ::msgcat::mcset ::msgcat::mcmset ::msgcat::mcunknown -# -# This file contains a collection of tests for the msgcat script library. +# This file contains a collection of tests for the msgcat package. # Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998 Mark Harrison. # Copyright (c) 1998-1999 by Scriptics Corporation. +# Contributions from Don Porter, NIST, 2002. (not subject to US copyright) # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: msgcat.test,v 1.10 2000/07/17 22:25:26 ericm Exp $ +# Note that after running these tests, entries will be left behind in the +# message catalogs for locales foo, foo_BAR, and foo_BAR_baz. +# +# RCS: @(#) $Id: msgcat.test,v 1.11 2002/06/17 05:37:39 dgp Exp $ -if {[lsearch [namespace children] ::tcltest] == -1} { - package require tcltest - namespace import -force ::tcltest::* +package require Tcl 8.2 +if {[catch {package require tcltest 2}]} { + puts stderr "Skipping tests in [info script]. tcltest 2 required." + return } +if {[catch {package require msgcat 1.3}]} { + puts stderr "Skipping tests in [info script]. No msgcat 1.3 found to test." + return +} + +namespace eval ::msgcat::test { + namespace import ::msgcat::* + namespace import ::tcltest::test + namespace import ::tcltest::cleanupTests + namespace import ::tcltest::temporaryDirectory + namespace import ::tcltest::make* + namespace import ::tcltest::remove* -if {[catch {package require msgcat 1.0}]} { - if {[info exist msgcat1]} { - catch {puts "Cannot load msgcat 1.0 package"} - return - } else { - catch {puts "Running msgcat 1.0 tests in slave interp"} - set interp [interp create msgcat1] - $interp eval [list set msgcat1 "running"] - $interp eval [list source [info script]] - interp delete $interp - return + # Tests msgcat-0.*: locale initialization + + proc PowerSet {l} { + if {[llength $l] == 0} {return [list [list]]} + set element [lindex $l 0] + set rest [lrange $l 1 end] + set result [list] + foreach x [PowerSet $rest] { + lappend result [linsert $x 0 $element] + lappend result $x + } + return $result } -} -set oldlocale [::msgcat::mclocale] + variable envVars {LC_ALL LC_MESSAGES LANG} + variable count 0 + variable body + variable result + variable setVars + foreach setVars [PowerSet $envVars] { + set result [string tolower [lindex $setVars 0]] + if {[string length $result] == 0} { + set result c + } + test msgcat-0.$count { + locale initialization from environment variables + } -setup { + variable var + foreach var $envVars { + catch {variable $var $::env($var)} + catch {unset ::env($var)} + } + foreach var $setVars { + set ::env($var) $var + } + interp create [namespace current]::i + i eval [list package ifneeded msgcat [package provide msgcat] \ + [package ifneeded msgcat [package provide msgcat]]] + i eval package require msgcat + } -cleanup { + interp delete [namespace current]::i + foreach var $envVars { + catch {unset ::env($var)} + catch {set ::env($var) [set [namespace current]::$var]} + } + } -body {i eval msgcat::mclocale} -result $result + incr count + } + catch {unset result} + + # Could add tests of initialization from Windows registry here. + # Use a fake registry package. -# some tests fail in tne environment variable LANG exists and is not C + # Tests msgcat-1.*: [mclocale], [mcpreferences] -if {[info exists env(LANG)] && ($env(LANG) != "C")} { - set ::tcltest::testConstraints(LANGisC) 0 -} else { - set ::tcltest::testConstraints(LANGisC) 1 -} + test msgcat-1.3 {mclocale set, single element} -setup { + variable locale [mclocale] + } -cleanup { + mclocale $locale + } -body { + mclocale en + } -result en -# -# Test the various permutations of mclocale -# and mcpreferences. -# + test msgcat-1.4 {mclocale get, single element} -setup { + variable locale [mclocale] + mclocale en + } -cleanup { + mclocale $locale + } -body { + mclocale + } -result en -test msgcat-1.1 {::msgcat::mclocale default} {LANGisC} { - ::msgcat::mclocale -} {c} -test msgcat-1.2 {::msgcat::mcpreferences, single element} {LANGisC} { - ::msgcat::mcpreferences -} {c} -test msgcat-1.3 {::msgcat::mclocale, single element} { - ::msgcat::mclocale en -} {en} -test msgcat-1.4 {::msgcat::mclocale, single element} { - ::msgcat::mclocale -} {en} -test msgcat-1.5 {::msgcat::mcpreferences, single element} { - ::msgcat::mcpreferences -} {en} -test msgcat-1.6 {::msgcat::mclocale, two elements} { - ::msgcat::mclocale en_US -} {en_us} -test msgcat-1.7 {::msgcat::mclocale, two elements} { - ::msgcat::mclocale en_US - ::msgcat::mclocale -} {en_us} -test msgcat-1.8 {::msgcat::mcpreferences, two elements} { - ::msgcat::mcpreferences -} {en_us en} -test msgcat-1.9 {::msgcat::mclocale, three elements} { - ::msgcat::mclocale en_US_funky -} {en_us_funky} -test msgcat-1.10 {::msgcat::mclocale, three elements} { - ::msgcat::mclocale -} {en_us_funky} -test msgcat-1.11 {::msgcat::mcpreferences, three elements} { - ::msgcat::mcpreferences -} {en_us_funky en_us en} + test msgcat-1.5 {mcpreferences, single element} -setup { + variable locale [mclocale] + mclocale en + } -cleanup { + mclocale $locale + } -body { + mcpreferences + } -result en -# -# Test mcset and mc, ensuring that namespace partitioning -# is working. -# + test msgcat-1.6 {mclocale set, two elements} -setup { + variable locale [mclocale] + } -cleanup { + mclocale $locale + } -body { + mclocale en_US + } -result en_us -test msgcat-2.1 {::msgcat::mcset, global scope} { - ::msgcat::mcset foo_BAR text1 text2 -} {text2} -test msgcat-2.2 {::msgcat::mcset, global scope, default} { - ::msgcat::mcset foo_BAR text3 -} {text3} -test msgcat-2.2 {::msgcat::mcset, namespace overlap} { - namespace eval bar {::msgcat::mcset foo_BAR con1 con1bar} - namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} -} {con1baz} -test msgcat-2.3 {::msgcat::mcset, namespace overlap} { - ::msgcat::mclocale foo_BAR - namespace eval bar {::msgcat::mc con1} -} {con1bar} -test msgcat-2.4 {::msgcat::mcset, namespace overlap} { - ::msgcat::mclocale foo_BAR - namespace eval baz {::msgcat::mc con1} -} {con1baz} -test msgcat-2.5 {::msgcat::mcmset, global scope} { - ::msgcat::mcmset foo_BAR { - src1 trans1 - src2 trans2 - } - ::msgcat::mc src1 -} {trans1} -test msgcat-2.6 {::msgcat::mcmset, namespace overlap} { - namespace eval bar {::msgcat::mcmset foo_BAR {con2 con2bar}} - namespace eval baz {::msgcat::mcmset foo_BAR {con2 con2baz}} -} {2} -test msgcat-2.7 {::msgcat::mcmset, namespace overlap} { - ::msgcat::mclocale foo_BAR - namespace eval baz {::msgcat::mc con2} -} {con2baz} + test msgcat-1.7 {mclocale get, two elements} -setup { + variable locale [mclocale] + mclocale en_US + } -cleanup { + mclocale $locale + } -body { + mclocale + } -result en_us + test msgcat-1.8 {mcpreferences, two elements} -setup { + variable locale [mclocale] + mclocale en_US + } -cleanup { + mclocale $locale + } -body { + mcpreferences + } -result {en_us en} -# -# Test mcset and mc, ensuring that more specific locales -# (e.g. "en_UK") will search less specific locales -# (e.g. "en") for translation strings. -# -# Do this for the 12 permutations of -# locales: {foo foo_BAR foo_BAR_baz} -# strings: {ov1 ov2 ov3 ov4} -# locale foo defines ov1, ov2, ov3 -# locale foo_BAR defines ov2, ov3 -# locale foo_BAR_BAZ defines ov3 -# (ov4 is defined in none) -# So, -# ov3 should be resolved in foo, foo_BAR, foo_BAR_baz -# ov2 should be resolved in foo, foo_BAR -# ov2 should resolve to foo_BAR in foo_BAR_baz -# ov1 should be resolved in foo -# ov1 should resolve to foo in foo_BAR, foo_BAR_baz -# ov4 should be resolved in none, and call mcunknown -# + test msgcat-1.9 {mclocale set, three elements} -setup { + variable locale [mclocale] + } -cleanup { + mclocale $locale + } -body { + mclocale en_US_funky + } -result en_us_funky -test msgcat-3.1 {::msgcat::mcset, overlap} { - ::msgcat::mcset foo ov1 ov1_foo - ::msgcat::mcset foo ov2 ov2_foo - ::msgcat::mcset foo ov3 ov3_foo - ::msgcat::mcset foo_BAR ov2 ov2_foo_BAR - ::msgcat::mcset foo_BAR ov3 ov3_foo_BAR - ::msgcat::mcset foo_BAR_baz ov3 ov3_foo_BAR_baz -} {ov3_foo_BAR_baz} -# top level, locale foo -test msgcat-3.2 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo - ::msgcat::mc ov1 -} {ov1_foo} -test msgcat-3.3 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo - ::msgcat::mc ov2 -} {ov2_foo} -test msgcat-3.4 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo - ::msgcat::mc ov3 -} {ov3_foo} -test msgcat-3.5 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo - ::msgcat::mc ov4 -} {ov4} -# second level, locale foo_BAR -test msgcat-3.6 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR - ::msgcat::mc ov1 -} {ov1_foo} -test msgcat-3.7 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR - ::msgcat::mc ov2 -} {ov2_foo_BAR} -test msgcat-3.8 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR - ::msgcat::mc ov3 -} {ov3_foo_BAR} -test msgcat-3.9 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR - ::msgcat::mc ov4 -} {ov4} -# third level, locale foo_BAR_baz -test msgcat-3.10 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR_baz - ::msgcat::mc ov1 -} {ov1_foo} -test msgcat-3.11 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR_baz - ::msgcat::mc ov2 -} {ov2_foo_BAR} -test msgcat-3.12 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR_baz - ::msgcat::mc ov3 -} {ov3_foo_BAR_baz} -test msgcat-3.13 {::msgcat::mcset, overlap} { - ::msgcat::mclocale foo_BAR_baz - ::msgcat::mc ov4 -} {ov4} + test msgcat-1.10 {mclocale get, three elements} -setup { + variable locale [mclocale] + mclocale en_US_funky + } -cleanup { + mclocale $locale + } -body { + mclocale + } -result en_us_funky -# -# Test mcunknown, first the default operation -# and then with an overridden definition. -# + test msgcat-1.11 {mcpreferences, three elements} -setup { + variable locale [mclocale] + mclocale en_US_funky + } -cleanup { + mclocale $locale + } -body { + mcpreferences + } -result {en_us_funky en_us en} + + # Tests msgcat-2.*: [mcset], [mcmset], namespace partitioning + + test msgcat-2.1 {mcset, global scope} { + namespace eval :: ::msgcat::mcset foo_BAR text1 text2 + } {text2} + + test msgcat-2.2 {mcset, global scope, default} { + namespace eval :: ::msgcat::mcset foo_BAR text3 + } {text3} + + test msgcat-2.2 {mcset, namespace overlap} { + namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} + } {con1baz} + + test msgcat-2.3 {mcset, namespace overlap} -setup { + namespace eval bar {::msgcat::mcset foo_BAR con1 con1bar} + namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + namespace eval bar {::msgcat::mc con1} + } -result con1bar + + test msgcat-2.4 {mcset, namespace overlap} -setup { + namespace eval bar {::msgcat::mcset foo_BAR con1 con1bar} + namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + namespace eval baz {::msgcat::mc con1} + } -result con1baz + + test msgcat-2.5 {mcmset, global scope} -setup { + namespace eval :: { + ::msgcat::mcmset foo_BAR { + src1 trans1 + src2 trans2 + } + } + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + namespace eval :: { + ::msgcat::mc src1 + } + } -result trans1 -test msgcat-4.1 {::msgcat::mcunknown, default} { - ::msgcat::mcset foo unk1 "unknown 1" -} {unknown 1} -test msgcat-4.2 {::msgcat::mcunknown, default} { - ::msgcat::mclocale foo - ::msgcat::mc unk1 -} {unknown 1} -test msgcat-4.3 {::msgcat::mcunknown, default} { - ::msgcat::mclocale foo - ::msgcat::mc unk2 -} {unk2} -test msgcat-4.4 {::msgcat::mcunknown, overridden} { - rename ::msgcat::mcunknown oldproc - proc ::msgcat::mcunknown {dom s} { - return "unknown:$dom:$s" + test msgcat-2.6 {mcmset, namespace overlap} -setup { + namespace eval bar {::msgcat::mcmset foo_BAR {con2 con2bar}} + namespace eval baz {::msgcat::mcmset foo_BAR {con2 con2baz}} + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + namespace eval bar {::msgcat::mc con2} + } -result con2bar + + test msgcat-2.7 {mcmset, namespace overlap} -setup { + namespace eval bar {::msgcat::mcmset foo_BAR {con2 con2bar}} + namespace eval baz {::msgcat::mcmset foo_BAR {con2 con2baz}} + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + namespace eval baz {::msgcat::mc con2} + } -result con2baz + + # Tests msgcat-3.*: [mcset], [mc], catalog "inheritance" + # + # Test mcset and mc, ensuring that more specific locales + # (e.g. en_UK) will search less specific locales + # (e.g. en) for translation strings. + # + # Do this for the 12 permutations of + # locales: {foo foo_BAR foo_BAR_baz} + # strings: {ov1 ov2 ov3 ov4} + # locale foo defines ov1, ov2, ov3 + # locale foo_BAR defines ov2, ov3 + # locale foo_BAR_BAZ defines ov3 + # (ov4 is defined in none) + # So, + # ov3 should be resolved in foo, foo_BAR, foo_BAR_baz + # ov2 should be resolved in foo, foo_BAR + # ov2 should resolve to foo_BAR in foo_BAR_baz + # ov1 should be resolved in foo + # ov1 should resolve to foo in foo_BAR, foo_BAR_baz + # ov4 should be resolved in none, and call mcunknown + # + variable count 2 + variable result + array set result { + foo,ov1 ov1_foo foo,ov2 ov2_foo foo,ov3 ov3_foo foo,ov4 ov4 + foo_BAR,ov1 ov1_foo foo_BAR,ov2 ov2_foo_BAR foo_BAR,ov3 ov3_foo_BAR + foo_BAR,ov4 ov4 foo_BAR_baz,ov1 ov1_foo foo_BAR_baz,ov2 ov2_foo_BAR + foo_BAR_baz,ov3 ov3_foo_BAR_baz foo_BAR_baz,ov4 ov4 } - ::msgcat::mclocale foo - set result [::msgcat::mc unk1] - rename ::msgcat::mcunknown {} - rename oldproc ::msgcat::mcunknown - set result -} {unknown 1} -test msgcat-4.5 {::msgcat::mcunknown, overridden} { - rename ::msgcat::mcunknown oldproc - proc ::msgcat::mcunknown {dom s} { - return "unknown:$dom:$s" + variable loc + variable string + foreach loc {foo foo_BAR foo_BAR_baz} { + foreach string {ov1 ov2 ov3 ov4} { + test msgcat-3.$count {mcset, overlap} -setup { + mcset foo ov1 ov1_foo + mcset foo ov2 ov2_foo + mcset foo ov3 ov3_foo + mcset foo_BAR ov2 ov2_foo_BAR + mcset foo_BAR ov3 ov3_foo_BAR + mcset foo_BAR_baz ov3 ov3_foo_BAR_baz + variable locale [mclocale] + mclocale $loc + } -cleanup { + mclocale $locale + } -body { + mc $string + } -result $result($loc,$string) + incr count + } } - ::msgcat::mclocale foo - set result [::msgcat::mc unk2] - rename ::msgcat::mcunknown {} - rename oldproc ::msgcat::mcunknown - set result -} {unknown:foo:unk2} -test msgcat-4.6 {::msgcat::mcunknown, uplevel context} { - rename ::msgcat::mcunknown oldproc - proc ::msgcat::mcunknown {dom s} { - return "unknown:$dom:$s:[info level]" + catch {unset result} + + # Tests msgcat-4.*: [mcunknown] + + test msgcat-4.2 {mcunknown, default} -setup { + mcset foo unk1 "unknown 1" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc unk1 + } -result {unknown 1} + + test msgcat-4.3 {mcunknown, default} -setup { + mcset foo unk1 "unknown 1" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc unk2 + } -result unk2 + + test msgcat-4.4 {mcunknown, overridden} -setup { + rename ::msgcat::mcunknown SavedMcunknown + proc ::msgcat::mcunknown {dom s} { + return unknown:$dom:$s + } + mcset foo unk1 "unknown 1" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + rename ::msgcat::mcunknown {} + rename SavedMcunknown ::msgcat::mcunknown + } -body { + mc unk1 + } -result {unknown 1} + + test msgcat-4.5 {mcunknown, overridden} -setup { + rename ::msgcat::mcunknown SavedMcunknown + proc ::msgcat::mcunknown {dom s} { + return unknown:$dom:$s + } + mcset foo unk1 "unknown 1" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + rename ::msgcat::mcunknown {} + rename SavedMcunknown ::msgcat::mcunknown + } -body { + mc unk2 + } -result {unknown:foo:unk2} + + test msgcat-4.6 {mcunknown, uplevel context} -setup { + rename ::msgcat::mcunknown SavedMcunknown + proc ::msgcat::mcunknown {dom s} { + return "unknown:$dom:$s:[expr {[info level] - 1}]" + } + mcset foo unk1 "unknown 1" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + rename ::msgcat::mcunknown {} + rename SavedMcunknown ::msgcat::mcunknown + } -body { + mc unk2 + } -result unknown:foo:unk2:[info level] + + # Tests msgcat-5.*: [mcload] + + variable locales {foo foo_BAR foo_BAR_baz} + makeDirectory msgdir + foreach loc $locales { + makeFile "::msgcat::mcset $loc abc abc-$loc" \ + [string tolower [file join msgdir $loc.msg]] + } + variable count 1 + foreach loc {foo foo_BAR foo_BAR_baz} { + test msgcat-5.$count {mcload} -setup { + variable locale [mclocale] + mclocale $loc + } -cleanup { + mclocale $locale + } -body { + mcload [file join [temporaryDirectory] msgdir] + } -result $count + incr count } - ::msgcat::mclocale foo - set result [::msgcat::mc unk2] - rename ::msgcat::mcunknown {} - rename oldproc ::msgcat::mcunknown - set result -} {unknown:foo:unk2:1} - -# -# Test mcload. Need to set up an environment for -# these tests by creating a temporary directory and -# message files. -# + # Even though foo_BAR_notexist does not exist, + # foo_BAR and foo should be loaded. + test msgcat-5.4 {mcload} -setup { + variable locale [mclocale] + mclocale foo_BAR_notexist + } -cleanup { + mclocale $locale + } -body { + mcload [file join [temporaryDirectory] msgdir] + } -result 2 -set locales {en en_US en_US_funky} + test msgcat-5.5 {mcload} -setup { + variable locale [mclocale] + mclocale no_FI_notexist + } -cleanup { + mclocale $locale + } -body { + mcload [file join [temporaryDirectory] msgdir] + } -result 0 -catch {file mkdir msgdir} -foreach l $locales { - set fd [open [string tolower [file join msgdir $l.msg]] w] - puts $fd "::msgcat::mcset $l abc abc-$l" - close $fd -} + test msgcat-5.6 {mcload} -setup { + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc abc + } -result abc-foo -test msgcat-5.1 {::msgcat::mcload} { - ::msgcat::mclocale en - ::msgcat::mcload msgdir -} {1} -test msgcat-5.2 {::msgcat::mcload} { - ::msgcat::mclocale en_US - ::msgcat::mcload msgdir -} {2} -test msgcat-5.3 {::msgcat::mcload} { - ::msgcat::mclocale en_US_funky - ::msgcat::mcload msgdir -} {3} - -# Even though en_US_notexist does not exist, -# en_US and en should be loaded. - -test msgcat-5.4 {::msgcat::mcload} { - ::msgcat::mclocale en_US_notexist - ::msgcat::mcload msgdir -} {2} -test msgcat-5.5 {::msgcat::mcload} { - ::msgcat::mclocale no_FI_notexist - ::msgcat::mcload msgdir -} {0} -test msgcat-5.6 {::msgcat::mcload} { - ::msgcat::mclocale en - ::msgcat::mc abc -} {abc-en} -test msgcat-5.7 {::msgcat::mcload} { - ::msgcat::mclocale en_US - ::msgcat::mc abc -} {abc-en_US} -test msgcat-5.8 {::msgcat::mcload} { - ::msgcat::mclocale en_US_funky - ::msgcat::mc abc -} {abc-en_US_funky} -test msgcat-5.9 {::msgcat::mcload} { - rename ::msgcat::mcunknown oldproc - proc ::msgcat::mcunknown {dom s} { - return "unknown:$dom:$s" + test msgcat-5.7 {mcload} -setup { + variable locale [mclocale] + mclocale foo_BAR + } -cleanup { + mclocale $locale + } -body { + mc abc + } -result abc-foo_BAR + + test msgcat-5.8 {mcload} -setup { + variable locale [mclocale] + mclocale foo_BAR_baz + } -cleanup { + mclocale $locale + } -body { + mc abc + } -result abc-foo_BAR_baz + + test msgcat-5.9 {mcload} -setup { + rename ::msgcat::mcunknown SavedMcunknown + proc ::msgcat::mcunknown {dom s} { + return unknown:$dom:$s + } + variable locale [mclocale] + mclocale no_FI_notexist + } -cleanup { + mclocale $locale + rename ::msgcat::mcunknown {} + rename SavedMcunknown ::msgcat::mcunknown + } -body { + mc abc + } -result unknown:no_fi_notexist:abc + + + foreach loc $locales { + removeFile [string tolower [file join msgdir $loc.msg]] } - ::msgcat::mclocale no_FI_notexist - set result [::msgcat::mc abc] - rename ::msgcat::mcunknown {} - rename oldproc ::msgcat::mcunknown - set result -} {unknown:no_fi_notexist:abc} - -# cleanup temp files -foreach l $locales { - file delete [string tolower [file join msgdir $l.msg]] -} -# Clean out the msg catalogs -file delete msgdir + removeDirectory msgdir + # Tests msgcat-6.*: [mcset], [mc] namespace inheritance # # Test mcset and mc, ensuring that resolution for messages # proceeds from the current ns to its parent and so on to the @@ -332,7 +459,7 @@ file delete msgdir # # Do this for the 12 permutations of # locales: foo -# namespaces: ::foo ::foo::bar ::foo::bar::baz +# namespaces: foo foo::bar foo::bar::baz # strings: {ov1 ov2 ov3 ov4} # namespace ::foo defines ov1, ov2, ov3 # namespace ::foo::bar defines ov2, ov3 @@ -347,82 +474,96 @@ file delete msgdir # ov4 should be resolved in none, and call mcunknown # -namespace eval ::foo { - ::msgcat::mcset foo ov1 "ov1_foo" - ::msgcat::mcset foo ov2 "ov2_foo" - ::msgcat::mcset foo ov3 "ov3_foo" + variable result + array set result { + foo,ov1 ov1_foo foo,ov2 ov2_foo foo,ov3 ov3_foo foo,ov4 ov4 + foo::bar,ov1 ov1_foo foo::bar,ov2 ov2_foo_bar + foo::bar,ov3 ov3_foo_bar foo::bar,ov4 ov4 foo::bar::baz,ov1 ov1_foo + foo::bar::baz,ov2 ov2_foo_bar foo::bar::baz,ov3 ov3_foo_bar_baz + foo::bar::baz,ov4 ov4 + } + variable count 1 + variable ns + foreach ns {foo foo::bar foo::bar::baz} { + foreach string {ov1 ov2 ov3 ov4} { + test msgcat-6.$count {mcset, overlap} -setup { + namespace eval foo { + ::msgcat::mcset foo ov1 ov1_foo + ::msgcat::mcset foo ov2 ov2_foo + ::msgcat::mcset foo ov3 ov3_foo + namespace eval bar { + ::msgcat::mcset foo ov2 ov2_foo_bar + ::msgcat::mcset foo ov3 ov3_foo_bar + namespace eval baz { + ::msgcat::mcset foo ov3 "ov3_foo_bar_baz" + } + } + + } + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + namespace delete foo + } -body { + namespace eval $ns [list ::msgcat::mc $string] + } -result $result($ns,$string) + incr count + } + } + + # Tests msgcat-7.*: [mc] extra args processed by [format] + + test msgcat-7.1 {mc extra args go through to format} -setup { + mcset foo format1 "this is a test" + mcset foo format2 "this is a %s" + mcset foo format3 "this is a %s %s" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc format1 "good test" + } -result "this is a test" + + test msgcat-7.2 {mc extra args go through to format} -setup { + mcset foo format1 "this is a test" + mcset foo format2 "this is a %s" + mcset foo format3 "this is a %s %s" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc format2 "good test" + } -result "this is a good test" + + test msgcat-7.3 {mc errors from format are propagated} -setup { + mcset foo format1 "this is a test" + mcset foo format2 "this is a %s" + mcset foo format3 "this is a %s %s" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + catch {mc format3 "good test"} + } -result 1 + + test msgcat-7.4 {mc, extra args are given to unknown} -setup { + mcset foo format1 "this is a test" + mcset foo format2 "this is a %s" + mcset foo format3 "this is a %s %s" + variable locale [mclocale] + mclocale foo + } -cleanup { + mclocale $locale + } -body { + mc "this is a %s" "good test" + } -result "this is a good test" + + cleanupTests } -namespace eval ::foo::bar { - ::msgcat::mcset foo ov2 "ov2_foo_bar" - ::msgcat::mcset foo ov3 "ov3_foo_bar" -} -namespace eval ::foo::bar::baz { - ::msgcat::mcset foo ov3 "ov3_foo_bar_baz" -} -::msgcat::mclocale foo - -# namespace ::foo -test msgcat-6.1 {::msgcat::mc, namespace resolution} { - namespace eval ::foo {::msgcat::mc ov1} -} {ov1_foo} -test msgcat-6.2 {::msgcat::mc, namespace resolution} { - namespace eval ::foo {::msgcat::mc ov2} -} {ov2_foo} -test msgcat-6.3 {::msgcat::mc, namespace resolution} { - namespace eval ::foo {::msgcat::mc ov3} -} {ov3_foo} -test msgcat-6.4 {::msgcat::mc, namespace resolution} { - namespace eval ::foo {::msgcat::mc ov4} -} {ov4} -# namespace ::foo::bar -test msgcat-6.5 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar {::msgcat::mc ov1} -} {ov1_foo} -test msgcat-6.6 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar {::msgcat::mc ov2} -} {ov2_foo_bar} -test msgcat-6.7 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar {::msgcat::mc ov3} -} {ov3_foo_bar} -test msgcat-6.8 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar {::msgcat::mc ov4} -} {ov4} -# namespace ::foo -test msgcat-6.9 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar::baz {::msgcat::mc ov1} -} {ov1_foo} -test msgcat-6.10 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar::baz {::msgcat::mc ov2} -} {ov2_foo_bar} -test msgcat-6.11 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar::baz {::msgcat::mc ov3} -} {ov3_foo_bar_baz} -test msgcat-6.12 {::msgcat::mc, namespace resolution} { - namespace eval ::foo::bar::baz {::msgcat::mc ov4} -} {ov4} - -namespace delete ::foo::bar::baz ::foo::bar ::foo - -::msgcat::mclocale foo -::msgcat::mcset foo format1 "this is a test" -::msgcat::mcset foo format2 "this is a %s" -::msgcat::mcset foo format3 "this is a %s %s" - -test msgcat-7.1 {::msgcat::mc, extra args go through to format} { - ::msgcat::mc format1 "good test" -} "this is a test" -test msgcat-7.2 {::msgcat::mc, extra args go through to format} { - ::msgcat::mc format2 "good test" -} "this is a good test" -test msgcat-7.3 {::msgcat::mc, errors from format are propagated} { - catch {::msgcat::mc format3 "good test"} -} 1 -test msgcat-7.4 {::msgcat::mc, extra args are given to unknown} { - ::msgcat::mc "this is a %s" "good test" -} "this is a good test" - -# Reset the locale -::msgcat::mclocale $oldlocale - -::tcltest::cleanupTests +namespace delete ::msgcat::test return + |