summaryrefslogtreecommitdiff
path: root/tcl/library/msgcat/msgcat.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'tcl/library/msgcat/msgcat.tcl')
-rw-r--r--tcl/library/msgcat/msgcat.tcl457
1 files changed, 457 insertions, 0 deletions
diff --git a/tcl/library/msgcat/msgcat.tcl b/tcl/library/msgcat/msgcat.tcl
new file mode 100644
index 00000000000..eb3b521976e
--- /dev/null
+++ b/tcl/library/msgcat/msgcat.tcl
@@ -0,0 +1,457 @@
+# msgcat.tcl --
+#
+# This file defines various procedures which implement a
+# message catalog facility for Tcl programs. It should be
+# loaded with the command "package require msgcat".
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# Copyright (c) 1998 by Mark Harrison.
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# RCS: @(#) $Id$
+
+package require Tcl 8.2
+# When the version number changes, be sure to update the pkgIndex.tcl file,
+# and the installation directory in the Makefiles.
+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 ""
+
+ # Records the list of locales to search
+ 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 {}
+
+ # Map of language codes used in Windows registry to those of ISO-639
+ array set WinRegToISO639 {
+ 01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ
+ 1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY
+ 2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH
+ 4001 ar_QA
+ 02 bg 0402 bg_BG
+ 03 ca 0403 ca_ES
+ 04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO
+ 05 cs 0405 cs_CZ
+ 06 da 0406 da_DK
+ 07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI
+ 08 el 0408 el_GR
+ 09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ
+ 1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ
+ 2c09 en_TT 3009 en_ZW 3409 en_PH
+ 0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR
+ 180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE
+ 2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY
+ 400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR
+ 0b fi 040b fi_FI
+ 0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU
+ 180c fr_MC
+ 0d he 040d he_IL
+ 0e hu 040e hu_HU
+ 0f is 040f is_IS
+ 10 it 0410 it_IT 0810 it_CH
+ 11 ja 0411 ja_JP
+ 12 ko 0412 ko_KR
+ 13 nl 0413 nl_NL 0813 nl_BE
+ 14 no 0414 no_NO 0814 nn_NO
+ 15 pl 0415 pl_PL
+ 16 pt 0416 pt_BR 0816 pt_PT
+ 17 rm 0417 rm_CH
+ 18 ro 0418 ro_RO
+ 19 ru
+ 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic
+ 1b sk 041b sk_SK
+ 1c sq 041c sq_AL
+ 1d sv 041d sv_SE 081d sv_FI
+ 1e th 041e th_TH
+ 1f tr 041f tr_TR
+ 20 ur 0420 ur_PK 0820 ur_IN
+ 21 id 0421 id_ID
+ 22 uk 0422 uk_UA
+ 23 be 0423 be_BY
+ 24 sl 0424 sl_SI
+ 25 et 0425 et_EE
+ 26 lv 0426 lv_LV
+ 27 lt 0427 lt_LT
+ 28 tg 0428 tg_TJ
+ 29 fa 0429 fa_IR
+ 2a vi 042a vi_VN
+ 2b hy 042b hy_AM
+ 2c az 042c az_AZ@latin 082c az_AZ@cyrillic
+ 2d eu
+ 2e wen 042e wen_DE
+ 2f mk 042f mk_MK
+ 30 bnt 0430 bnt_TZ
+ 31 ts 0431 ts_ZA
+ 33 ven 0433 ven_ZA
+ 34 xh 0434 xh_ZA
+ 35 zu 0435 zu_ZA
+ 36 af 0436 af_ZA
+ 37 ka 0437 ka_GE
+ 38 fo 0438 fo_FO
+ 39 hi 0439 hi_IN
+ 3a mt 043a mt_MT
+ 3b se 043b se_NO
+ 043c gd_UK 083c ga_IE
+ 3d yi 043d yi_IL
+ 3e ms 043e ms_MY 083e ms_BN
+ 3f kk 043f kk_KZ
+ 40 ky 0440 ky_KG
+ 41 sw 0441 sw_KE
+ 42 tk 0442 tk_TM
+ 43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic
+ 44 tt 0444 tt_RU
+ 45 bn 0445 bn_IN
+ 46 pa 0446 pa_IN
+ 47 gu 0447 gu_IN
+ 48 or 0448 or_IN
+ 49 ta
+ 4a te 044a te_IN
+ 4b kn 044b kn_IN
+ 4c ml 044c ml_IN
+ 4d as 044d as_IN
+ 4e mr 044e mr_IN
+ 4f sa 044f sa_IN
+ 50 mn
+ 51 bo 0451 bo_CN
+ 52 cy 0452 cy_GB
+ 53 km 0453 km_KH
+ 54 lo 0454 lo_LA
+ 55 my 0455 my_MM
+ 56 gl 0456 gl_ES
+ 57 kok 0457 kok_IN
+ 58 mni 0458 mni_IN
+ 59 sd
+ 5a syr 045a syr_TR
+ 5b si 045b si_LK
+ 5c chr 045c chr_US
+ 5d iu 045d iu_CA
+ 5e am 045e am_ET
+ 5f ber 045f ber_MA
+ 60 ks 0460 ks_PK 0860 ks_IN
+ 61 ne 0461 ne_NP 0861 ne_IN
+ 62 fy 0462 fy_NL
+ 63 ps
+ 64 tl 0464 tl_PH
+ 65 div 0465 div_MV
+ 66 bin 0466 bin_NG
+ 67 ful 0467 ful_NG
+ 68 ha 0468 ha_NG
+ 69 nic 0469 nic_NG
+ 6a yo 046a yo_NG
+ 70 ibo 0470 ibo_NG
+ 71 kau 0471 kau_NG
+ 72 om 0472 om_ET
+ 73 ti 0473 ti_ET
+ 74 gn 0474 gn_PY
+ 75 cpe 0475 cpe_US
+ 76 la 0476 la_VA
+ 77 so 0477 so_SO
+ 78 sit 0478 sit_CN
+ 79 pap 0479 pap_AN
+ }
+}
+
+# msgcat::mc --
+#
+# Find the translation for the given string based on the current
+# 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. 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.
+
+ 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)]} {
+ if {[llength $args] == 0} {
+ return $Msgs($loc,$ns,$src)
+ } else {
+ return [uplevel 1 \
+ [linsert $args 0 ::format $Msgs($loc,$ns,$src)]]
+ }
+ }
+ }
+ set ns [namespace parent $ns]
+ }
+ # we have not found the translation
+ return [uplevel 1 \
+ [linsert $args 0 [::namespace origin mcunknown] $Locale $src]]
+}
+
+# msgcat::mclocale --
+#
+# Query or set the current locale.
+#
+# Arguments:
+# newLocale (Optional) The new locale string. Locale strings
+# should be composed of one or more sublocale parts
+# separated by underscores (e.g. en_US).
+#
+# Results:
+# Returns the current locale.
+
+proc msgcat::mclocale {args} {
+ variable Loclist
+ variable Locale
+ set len [llength $args]
+
+ if {$len > 1} {
+ error {wrong # args: should be "mclocale ?newLocale?"}
+ }
+
+ if {$len == 1} {
+ set Locale [string tolower [lindex $args 0]]
+ set Loclist {}
+ set word ""
+ foreach part [split $Locale _] {
+ set word [string trimleft "${word}_${part}" _]
+ set Loclist [linsert $Loclist 0 $word]
+ }
+ }
+ return $Locale
+}
+
+# msgcat::mcpreferences --
+#
+# Fetch the list of locales used to look up strings, ordered from
+# most preferred to least preferred.
+#
+# Arguments:
+# None.
+#
+# Results:
+# Returns an ordered list of the locales preferred by the user.
+
+proc msgcat::mcpreferences {} {
+ variable Loclist
+ return $Loclist
+}
+
+# msgcat::mcload --
+#
+# Attempt to load message catalogs for each locale in the
+# preference list from the specified directory.
+#
+# Arguments:
+# langdir The directory to search.
+#
+# Results:
+# Returns the number of message catalogs that were loaded.
+
+proc msgcat::mcload {langdir} {
+ set x 0
+ foreach p [mcpreferences] {
+ set langfile [file join $langdir $p.msg]
+ if {[file exists $langfile]} {
+ incr x
+ set fid [open $langfile "r"]
+ fconfigure $fid -encoding utf-8
+ uplevel 1 [read $fid]
+ close $fid
+ }
+ }
+ return $x
+}
+
+# msgcat::mcset --
+#
+# Set the translation for a given string in a specified locale.
+#
+# Arguments:
+# locale The locale to use.
+# src The source string.
+# dest (Optional) The translated string. If omitted,
+# the source string is used.
+#
+# Results:
+# Returns the new locale.
+
+proc msgcat::mcset {locale src {dest ""}} {
+ variable Msgs
+ if {[string equal $dest ""]} {
+ set dest $src
+ }
+
+ set ns [uplevel 1 [list ::namespace current]]
+
+ set Msgs([string tolower $locale],$ns,$src) $dest
+ return $dest
+}
+
+# msgcat::mcmset --
+#
+# Set the translation for multiple strings in a specified locale.
+#
+# Arguments:
+# locale The locale to use.
+# pairs One or more src/dest pairs (must be even length)
+#
+# Results:
+# Returns the number of pairs processed
+
+proc msgcat::mcmset {locale pairs } {
+ variable Msgs
+
+ set length [llength $pairs]
+ if {$length % 2} {
+ error {bad translation list: should be "mcmset locale {src dest ...}"}
+ }
+
+ set locale [string tolower $locale]
+ set ns [uplevel 1 [list ::namespace current]]
+
+ foreach {src dest} $pairs {
+ set Msgs($locale,$ns,$src) $dest
+ }
+
+ return $length
+}
+
+# msgcat::mcunknown --
+#
+# This routine is called by msgcat::mc if a translation cannot
+# be found for a string. This routine is intended to be replaced
+# by an application specific routine for error reporting
+# purposes. The default behavior is to return the source string.
+# If additional args are specified, the format command will be used
+# to work them into the traslated string.
+#
+# Arguments:
+# locale The current locale.
+# src The string to be translated.
+# args Args to pass to the format command
+#
+# Results:
+# Returns the translated value.
+
+proc msgcat::mcunknown {locale src args} {
+ if {[llength $args]} {
+ return [uplevel 1 [linsert $args 0 ::format $src]]
+ } else {
+ return $src
+ }
+}
+
+# msgcat::mcmax --
+#
+# Calculates the maximun length of the translated strings of the given
+# list.
+#
+# Arguments:
+# args strings to translate.
+#
+# Results:
+# Returns the length of the longest translated string.
+
+proc msgcat::mcmax {args} {
+ set max 0
+ foreach string $args {
+ set translated [uplevel 1 [list [namespace origin mc] $string]]
+ set len [string length $translated]
+ if {$len>$max} {
+ set max $len
+ }
+ }
+ return $max
+}
+
+# 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
+}
+
+# Initialize the default locale
+proc msgcat::Init {} {
+ #
+ # set default locale, try to get from environment
+ #
+ 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 [ConvertLocale $WinRegToISO639($locale)]}]} {
+ return
+ }
+ set locale [string range $locale 1 end]
+ }
+ #
+ # No translation known. Fall back on "C" locale
+ #
+ mclocale C
+}
+msgcat::Init