diff options
Diffstat (limited to 'library/msgcat/msgcat.tcl')
-rw-r--r-- | library/msgcat/msgcat.tcl | 191 |
1 files changed, 143 insertions, 48 deletions
diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index ccf4054..cf3b9d7 100644 --- a/library/msgcat/msgcat.tcl +++ b/library/msgcat/msgcat.tcl @@ -9,17 +9,15 @@ # # 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.26 2006/11/03 00:34:52 hobbs Exp $ package require Tcl 8.5 # When the version number changes, be sure to update the pkgIndex.tcl file, # and the installation directory in the Makefiles. -package provide msgcat 1.4.2 +package provide msgcat 1.5.2 namespace eval msgcat { namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \ - mcunknown + mcunknown mcflset mcflmset # Records the current locale as passed to mclocale variable Locale "" @@ -27,6 +25,9 @@ namespace eval msgcat { # Records the list of locales to search variable Loclist {} + # Records the locale of the currently sourced message catalogue file + variable FileLocale + # Records the mapping between source strings and translated strings. The # dict key is of the form "<locale> <namespace> <src>", where locale and # namespace should be themselves dict values and the value is @@ -34,7 +35,7 @@ namespace eval msgcat { variable Msgs [dict create] # Map of language codes used in Windows registry to those of ISO-639 - if { $::tcl_platform(platform) eq "windows" } { + if {[info sharedlibextension] eq ".dll"} { variable WinRegToISO639 [dict create {*}{ 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 @@ -68,8 +69,8 @@ namespace eval msgcat { 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 + 18 ro 0418 ro_RO 0818 ro_MO + 19 ru 0819 ru_MO 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic 1b sk 041b sk_SK 1c sq 041c sq_AL @@ -94,6 +95,7 @@ namespace eval msgcat { 2f mk 042f mk_MK 30 bnt 0430 bnt_TZ 31 ts 0431 ts_ZA + 32 tn 33 ven 0433 ven_ZA 34 xh 0434 xh_ZA 35 zu 0435 zu_ZA @@ -177,7 +179,7 @@ namespace eval msgcat { # args Args to pass to the format command # # Results: -# Returns the translated string. Propagates errors thrown by the +# Returns the translated string. Propagates errors thrown by the # format command. proc msgcat::mc {src args} { @@ -189,7 +191,7 @@ proc msgcat::mc {src args} { variable Locale set ns [uplevel 1 [list ::namespace current]] - + while {$ns != ""} { foreach loc $Loclist { if {[dict exists $Msgs $loc $ns $src]} { @@ -278,17 +280,30 @@ proc msgcat::mcpreferences {} { # Returns the number of message catalogs that were loaded. proc msgcat::mcload {langdir} { + variable FileLocale + # Save the file locale if we are recursively called + if {[info exists FileLocale]} { + set nestedFileLocale $FileLocale + } set x 0 foreach p [mcpreferences] { - if { $p eq {} } { + if {$p eq {}} { set p ROOT } set langfile [file join $langdir $p.msg] if {[file exists $langfile]} { incr x + set FileLocale [string tolower [file tail [file rootname $langfile]]] + if {"root" eq $FileLocale} { + set FileLocale "" + } uplevel 1 [list ::source -encoding utf-8 $langfile] + unset FileLocale } } + if {[info exists nestedFileLocale]} { + set FileLocale $nestedFileLocale + } return $x } @@ -312,17 +327,39 @@ proc msgcat::mcset {locale src {dest ""}} { } set ns [uplevel 1 [list ::namespace current]] - + set locale [string tolower $locale] - - # create nested dictionaries if they do not exist - if {![dict exists $Msgs $locale]} { - dict set Msgs $locale [dict create] + + dict set Msgs $locale $ns $src $dest + return $dest +} + +# msgcat::mcflset -- +# +# Set the translation for a given string in the current file locale. +# +# Arguments: +# src The source string. +# dest (Optional) The translated string. If omitted, +# the source string is used. +# +# Results: +# Returns the new locale. + +proc msgcat::mcflset {src {dest ""}} { + variable FileLocale + variable Msgs + + if {![info exists FileLocale]} { + return -code error \ + "must only be used inside a message catalog loaded with ::msgcat::mcload" } - if {![dict exists $Msgs $locale $ns]} { - dict set Msgs $locale $ns [dict create] + if {[llength [info level 0]] == 2} { ;# dest not specified + set dest $src } - dict set Msgs $locale $ns $src $dest + + set ns [uplevel 1 [list ::namespace current]] + dict set Msgs $FileLocale $ns $src $dest return $dest } @@ -337,7 +374,7 @@ proc msgcat::mcset {locale src {dest ""}} { # Results: # Returns the number of pairs processed -proc msgcat::mcmset {locale pairs } { +proc msgcat::mcmset {locale pairs} { variable Msgs set length [llength $pairs] @@ -345,22 +382,46 @@ proc msgcat::mcmset {locale pairs } { return -code error "bad translation list:\ should be \"[lindex [info level 0] 0] locale {src dest ...}\"" } - + set locale [string tolower $locale] set ns [uplevel 1 [list ::namespace current]] - # create nested dictionaries if they do not exist - if {![dict exists $Msgs $locale]} { - dict set Msgs $locale [dict create] - } - if {![dict exists $Msgs $locale $ns]} { - dict set Msgs $locale $ns [dict create] - } foreach {src dest} $pairs { - dict set Msgs $locale $ns $src $dest + dict set Msgs $locale $ns $src $dest } - return $length + return [expr {$length / 2}] +} + +# msgcat::mcflmset -- +# +# Set the translation for multiple strings in the mc file locale. +# +# Arguments: +# pairs One or more src/dest pairs (must be even length) +# +# Results: +# Returns the number of pairs processed + +proc msgcat::mcflmset {pairs} { + variable FileLocale + variable Msgs + + if {![info exists FileLocale]} { + return -code error \ + "must only be used inside a message catalog loaded with ::msgcat::mcload" + } + set length [llength $pairs] + if {$length % 2} { + return -code error "bad translation list:\ + should be \"[lindex [info level 0] 0] locale {src dest ...}\"" + } + + set ns [uplevel 1 [list ::namespace current]] + foreach {src dest} $pairs { + dict set Msgs $FileLocale $ns $src $dest + } + return [expr {$length / 2}] } # msgcat::mcunknown -- @@ -368,7 +429,7 @@ proc msgcat::mcmset {locale pairs } { # 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. +# 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. # @@ -390,7 +451,7 @@ proc msgcat::mcunknown {locale src args} { # msgcat::mcmax -- # -# Calculates the maximum length of the translated strings of the given +# Calculates the maximum length of the translated strings of the given # list. # # Arguments: @@ -403,10 +464,10 @@ 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 len [string length $translated] + if {$len>$max} { set max $len - } + } } return $max } @@ -442,13 +503,15 @@ proc msgcat::ConvertLocale {value} { # Initialize the default locale proc msgcat::Init {} { + global env + # # set default locale, try to get from environment # foreach varName {LC_ALL LC_MESSAGES LANG} { - if {[info exists ::env($varName)] && ("" ne $::env($varName))} { + if {[info exists env($varName)] && ("" ne $env($varName))} { if {![catch { - mclocale [ConvertLocale $::env($varName)] + mclocale [ConvertLocale $env($varName)] }]} { return } @@ -457,8 +520,7 @@ proc msgcat::Init {} { # # On Darwin, fallback to current CFLocale identifier if available. # - if {$::tcl_platform(os) eq "Darwin" && $::tcl_platform(platform) eq "unix" - && [info exists ::tcl::mac::locale] && $::tcl::mac::locale ne ""} { + if {[info exists ::tcl::mac::locale] && $::tcl::mac::locale ne ""} { if {![catch { mclocale [ConvertLocale $::tcl::mac::locale] }]} { @@ -466,21 +528,54 @@ proc msgcat::Init {} { } } # - # The rest of this routine is special processing for Windows; - # all other platforms, get out now. + # The rest of this routine is special processing for Windows or + # Cygwin. All other platforms, get out now. # - if { $::tcl_platform(platform) ne "windows" } { + if {([info sharedlibextension] ne ".dll") + || [catch {package require registry}]} { mclocale C return } # - # On Windows, try to set locale depending on registry settings, - # or fall back on locale of "C". + # On Windows or Cygwin, try to set locale depending on registry + # settings, or fall back on locale of "C". # - set key {HKEY_CURRENT_USER\Control Panel\International} - if {[catch {package require registry}] \ - || [catch {registry get $key "locale"} locale]} { - mclocale C + + # On Vista and later: + # HCU/Control Panel/Desktop : PreferredUILanguages is for language packs, + # HCU/Control Pannel/International : localName is the default locale. + # + # They contain the local string as RFC5646, composed of: + # [a-z]{2,3} : language + # -[a-z]{4} : script (optional, translated by table Latn->latin) + # -[a-z]{2}|[0-9]{3} : territory (optional, numerical region codes not used) + # (-.*)* : variant, extension, private use (optional, not used) + # Those are translated to local strings. + # Examples: de-CH -> de_ch, sr-Latn-CS -> sr_cs@latin, es-419 -> es + # + foreach key {{HKEY_CURRENT_USER\Control Panel\Desktop} {HKEY_CURRENT_USER\Control Panel\International}}\ + value {PreferredUILanguages localeName} { + if {![catch {registry get $key $value} localeName] + && [regexp {^([a-z]{2,3})(?:-([a-z]{4}))?(?:-([a-z]{2}))?(?:-.+)?$}\ + [string tolower $localeName] match locale script territory]} { + if {"" ne $territory} { + append locale _ $territory + } + set modifierDict [dict create latn latin cyrl cyrillic] + if {[dict exists $modifierDict $script]} { + append locale @ [dict get $modifierDict $script] + } + if {![catch {mclocale [ConvertLocale $locale]}]} { + return + } + } + } + + # then check value locale which contains a numerical language ID + if {[catch { + set locale [registry get $key "locale"] + }]} { + mclocale C return } # @@ -496,7 +591,7 @@ proc msgcat::Init {} { set locale [string tolower $locale] while {[string length $locale]} { if {![catch { - mclocale [ConvertLocale [dict get $WinRegToISO639 $locale]] + mclocale [ConvertLocale [dict get $WinRegToISO639 $locale]] }]} { return } |