summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorericm <ericm>2000-04-11 21:16:17 (GMT)
committerericm <ericm>2000-04-11 21:16:17 (GMT)
commit6778b65f1b617527d2402c8b78b3419fb2a7c502 (patch)
tree389eff9702dc67f07d9f389d1d1412c6d33cca94
parent4e6c3f6a1d64a7586316c4c78bf4322877b8f075 (diff)
downloadtcl-6778b65f1b617527d2402c8b78b3419fb2a7c502.zip
tcl-6778b65f1b617527d2402c8b78b3419fb2a7c502.tar.gz
tcl-6778b65f1b617527d2402c8b78b3419fb2a7c502.tar.bz2
* msgcat.n: Added docs for new behavior from patch in [Bug: 4158].
* msgcat.test: Added tests for new behavior from patch in [Bug: 4158]. * msgcat.tcl: Applied patch from [Bug: 4158], which enables msgcat::mc to search the entire namespace ancestry chain for message translations (ie, first it checks the current namespace, then the parent, then the parent's parent, etc). Also allows the specification of additional args for msgcat::mc; if extra args are given, the [format] command is used to substitute the additional args in the translated message.
-rw-r--r--doc/msgcat.n42
-rw-r--r--library/msgcat/msgcat.tcl32
-rw-r--r--library/msgcat1.0/msgcat.tcl32
-rw-r--r--tests/msgcat.test102
4 files changed, 187 insertions, 21 deletions
diff --git a/doc/msgcat.n b/doc/msgcat.n
index 748d023..37c2a76 100644
--- a/doc/msgcat.n
+++ b/doc/msgcat.n
@@ -43,10 +43,17 @@ wishes to be enabled for multi-lingual applications.
.SH COMMANDS
.TP
-\fB::msgcat::mc \fIsrc-string\fR
+\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR?
Returns a translation of \fIsrc-string\fR according to the
-user's current locale. If no translation string
-exists, \fB::msgcat::mcunknown\fR is called and the string
+user's current locale. If additional arguments past \fIsrc-string\fR
+are given, the \fBformat\fR command is used to substitute the
+additional arguments in the translation of \fIsrc-string\fR.
+
+\fB::msgcat::mc\fR will search the messages defined
+in the current namespace for a translation of \fIsrc-string\fR; if
+none is found, it will search in the parent of the current namespace,
+and so on until it reaches the global namespace. If no translation
+string exists, \fB::msgcat::mcunknown\fR is called and the string
returned from \fB::msgcat::mcunknown\fR is returned.
.PP
\fB::msgcat::mc\fR is the main function used to localize an
@@ -137,6 +144,35 @@ will print
hello from ::
hello from ::foo
.CE
+.PP
+When searching for a translation of a message, the
+message catalog will search first the current namespace,
+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
+.CS
+mcset en m1 ":: message1"
+mcset en m2 ":: message2"
+mcset en m3 ":: message3"
+namespace eval ::foo {
+ mcset en m2 "::foo message2"
+ mcset en m3 "::foo message3"
+}
+namespace eval ::foo::bar {
+ mcset en m3 "::foo::bar message3"
+}
+puts "[mc m1]; [mc m2]; [mc m3]"
+namespace eval ::foo {puts "[mc m1]; [mc m2]; [mc m3]"}
+namespace eval ::foo::bar {puts "[mc m1]; [mc m2]; [mc m3]"}
+.CE
+will print
+.CS
+:: message1; :: message2; :: message3
+:: message1; ::foo message2; ::foo message3
+:: message1; ::foo message2; ::foo::bar message3
+.CE
.SH "LOCATION AND FORMAT OF MESSAGE FILES"
.PP
diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl
index 7eb1f90..4619ae1 100644
--- a/library/msgcat/msgcat.tcl
+++ b/library/msgcat/msgcat.tcl
@@ -10,7 +10,7 @@
# 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.3 1999/08/19 02:59:49 hobbs Exp $
+# RCS: @(#) $Id: msgcat.tcl,v 1.4 2000/04/11 21:16:18 ericm Exp $
package provide msgcat 1.0
@@ -32,20 +32,38 @@ namespace eval msgcat {
# msgcat::mc --
#
# Find the translation for the given string based on the current
-# locale setting.
+# locale setting. Check the local namespace first, then look in each
+# parent namespace until the source is found. If additional args are
+# specified, use the format command to work them into the traslated
+# string.
#
# Arguments:
# src The string to translate.
+# args Args to pass to the format command
#
# Results:
-# Returns the translatd string.
+# Returns the translatd string. Propagates errors thrown by the
+# format command.
+
+proc msgcat::mc {src args} {
+ # Check for the src in each namespace starting from the local and
+ # ending in the global.
-proc msgcat::mc {src} {
set ns [uplevel {namespace current}]
- foreach loc $::msgcat::loclist {
- if {[info exists ::msgcat::msgs($loc,$ns,$src)]} {
- return $::msgcat::msgs($loc,$ns,$src)
+
+ while {$ns != ""} {
+ foreach loc $::msgcat::loclist {
+ if {[info exists ::msgcat::msgs($loc,$ns,$src)]} {
+ if {[llength $args] == 0} {
+ return $::msgcat::msgs($loc,$ns,$src)
+ } else {
+ return [eval \
+ [list format $::msgcat::msgs($loc,$ns,$src)] \
+ $args]
+ }
+ }
}
+ set ns [namespace parent $ns]
}
# we have not found the translation
return [uplevel 1 [list [namespace origin mcunknown] \
diff --git a/library/msgcat1.0/msgcat.tcl b/library/msgcat1.0/msgcat.tcl
index 7eb1f90..4619ae1 100644
--- a/library/msgcat1.0/msgcat.tcl
+++ b/library/msgcat1.0/msgcat.tcl
@@ -10,7 +10,7 @@
# 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.3 1999/08/19 02:59:49 hobbs Exp $
+# RCS: @(#) $Id: msgcat.tcl,v 1.4 2000/04/11 21:16:18 ericm Exp $
package provide msgcat 1.0
@@ -32,20 +32,38 @@ namespace eval msgcat {
# msgcat::mc --
#
# Find the translation for the given string based on the current
-# locale setting.
+# locale setting. Check the local namespace first, then look in each
+# parent namespace until the source is found. If additional args are
+# specified, use the format command to work them into the traslated
+# string.
#
# Arguments:
# src The string to translate.
+# args Args to pass to the format command
#
# Results:
-# Returns the translatd string.
+# Returns the translatd string. Propagates errors thrown by the
+# format command.
+
+proc msgcat::mc {src args} {
+ # Check for the src in each namespace starting from the local and
+ # ending in the global.
-proc msgcat::mc {src} {
set ns [uplevel {namespace current}]
- foreach loc $::msgcat::loclist {
- if {[info exists ::msgcat::msgs($loc,$ns,$src)]} {
- return $::msgcat::msgs($loc,$ns,$src)
+
+ while {$ns != ""} {
+ foreach loc $::msgcat::loclist {
+ if {[info exists ::msgcat::msgs($loc,$ns,$src)]} {
+ if {[llength $args] == 0} {
+ return $::msgcat::msgs($loc,$ns,$src)
+ } else {
+ return [eval \
+ [list format $::msgcat::msgs($loc,$ns,$src)] \
+ $args]
+ }
+ }
}
+ set ns [namespace parent $ns]
}
# we have not found the translation
return [uplevel 1 [list [namespace origin mcunknown] \
diff --git a/tests/msgcat.test b/tests/msgcat.test
index c9c3eca..04e570b 100644
--- a/tests/msgcat.test
+++ b/tests/msgcat.test
@@ -12,7 +12,7 @@
# 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.7 2000/04/10 17:19:02 ericm Exp $
+# RCS: @(#) $Id: msgcat.test,v 1.8 2000/04/11 21:16:18 ericm Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest
@@ -302,14 +302,108 @@ test msgcat-5.9 {::msgcat::mcload} {
set result
} {unknown:no_fi_notexist:abc}
-# cleanup
+# cleanup temp files
foreach l $locales {
file delete [string tolower [file join msgdir $l.msg]]
}
-
# Clean out the msg catalogs
-::msgcat::mclocale $oldlocale
file delete msgdir
+#
+# Test mcset and mc, ensuring that resolution for messages
+# proceeds from the current ns to its parent and so on to the
+# global ns.
+#
+# Do this for the 12 permutations of
+# locales: foo
+# namespaces: ::foo ::foo::bar ::foo::bar::baz
+# strings: {ov1 ov2 ov3 ov4}
+# namespace ::foo defines ov1, ov2, ov3
+# namespace ::foo::bar defines ov2, ov3
+# namespace ::foo::bar::baz defines ov3
+#
+# ov4 is not defined in any namespace.
+#
+# So,
+# ov3 should be resolved in ::foo::bar::baz, ::foo::bar, ::foo;
+# ov2 should be resolved in ::foo, ::foo::bar
+# ov1 should be resolved in ::foo
+# 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"
+}
+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
+
+# Reset the locale
+::msgcat::mclocale $oldlocale
+
::tcltest::cleanupTests
return