diff options
Diffstat (limited to 'library/msgcat/msgcat.tcl')
| -rw-r--r-- | library/msgcat/msgcat.tcl | 242 | 
1 files changed, 181 insertions, 61 deletions
| diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index 907e35e..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.17.2.6 2006/09/10 18:23:45 dgp Exp $ -package require Tcl 8.2 +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.3.4 +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,14 +25,18 @@ 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 -    # array key is of the form "<locale>,<namespace>,<src>" and the value is +    # dict key is of the form "<locale> <namespace> <src>", where locale and +    # namespace should be themselves dict values and the value is      # the translated string. -    array set Msgs {} +    variable Msgs [dict create]      # Map of language codes used in Windows registry to those of ISO-639 -    if { [string equal $::tcl_platform(platform) windows] } { -	array set WinRegToISO639 { +    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  		  2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH @@ -67,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 @@ -93,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 @@ -159,7 +162,7 @@ namespace eval msgcat {  	    77 so 0477 so_SO  	    78 sit 0478 sit_CN  	    79 pap 0479 pap_AN -	} +	}]      }  } @@ -176,7 +179,7 @@ namespace eval msgcat {  #	args	Args to pass to the format command  #  # Results: -#	Returns the translatd string.  Propagates errors thrown by the  +#	Returns the translated string.  Propagates errors thrown by the  #	format command.  proc msgcat::mc {src args} { @@ -188,23 +191,22 @@ proc msgcat::mc {src args} {      variable Locale      set ns [uplevel 1 [list ::namespace current]] -     +      while {$ns != ""} {  	foreach loc $Loclist { -	    if {[info exists Msgs($loc,$ns,$src)]} { +	    if {[dict exists $Msgs $loc $ns $src]} {  		if {[llength $args] == 0} { -		    return $Msgs($loc,$ns,$src) +		    return [dict get $Msgs $loc $ns $src]  		} else { -		    return [uplevel 1 \ -			    [linsert $args 0 ::format $Msgs($loc,$ns,$src)]] +		    return [format [dict get $Msgs $loc $ns $src] {*}$args]  		}  	    }  	}  	set ns [namespace parent $ns]      }      # we have not found the translation -    return [uplevel 1 \ -	    [linsert $args 0 [::namespace origin mcunknown] $Locale $src]] +    return [uplevel 1 [list [namespace origin mcunknown] \ +	    $Locale $src {*}$args]]  }  # msgcat::mclocale -- @@ -225,7 +227,8 @@ proc msgcat::mclocale {args} {      set len [llength $args]      if {$len > 1} { -	error {wrong # args: should be "mclocale ?newLocale?"} +	return -code error "wrong # args: should be\ +		\"[lindex [info level 0] 0] ?newLocale?\""      }      if {$len == 1} { @@ -238,9 +241,13 @@ proc msgcat::mclocale {args} {  	set Loclist {}  	set word ""  	foreach part [split $Locale _] { -	    set word [string trimleft "${word}_${part}" _] -	    set Loclist [linsert $Loclist 0 $word] +	    set word [string trim "${word}_${part}" _] +	    if {$word ne [lindex $Loclist 0]} { +		set Loclist [linsert $Loclist 0 $word] +	    }  	} +	lappend Loclist {} +	set Locale [lindex $Loclist 0]      }      return $Locale  } @@ -273,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 {}} { +	    set p ROOT +	}  	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 +	    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  } @@ -303,12 +323,43 @@ proc msgcat::mcload {langdir} {  proc msgcat::mcset {locale src {dest ""}} {      variable Msgs      if {[llength [info level 0]] == 3} { ;# dest not specified -        set dest $src +	set dest $src      }      set ns [uplevel 1 [list ::namespace current]] -    set Msgs([string tolower $locale],$ns,$src) $dest +    set locale [string tolower $locale] + +    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 {[llength [info level 0]] == 2} { ;# dest not specified +	set dest $src +    } + +    set ns [uplevel 1 [list ::namespace current]] +    dict set Msgs $FileLocale $ns $src $dest      return $dest  } @@ -323,22 +374,54 @@ 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]      if {$length % 2} { -	error {bad translation list: should be "mcmset locale {src dest ...}"} +	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]] -     +      foreach {src dest} $pairs { -        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 -- @@ -346,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.  # @@ -360,7 +443,7 @@ proc msgcat::mcmset {locale pairs } {  proc msgcat::mcunknown {locale src args} {      if {[llength $args]} { -	return [uplevel 1 [linsert $args 0 ::format $src]] +	return [format $src {*}$args]      } else {  	return $src      } @@ -368,7 +451,7 @@ proc msgcat::mcunknown {locale src args} {  # msgcat::mcmax --  # -#	Calculates the maximun length of the translated strings of the given  +#	Calculates the maximum length of the translated strings of the given  #	list.  #  # Arguments: @@ -381,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 max $len -        } +	set len [string length $translated] +	if {$len>$max} { +	    set max $len +	}      }      return $max  } @@ -420,13 +503,16 @@ 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)]  -		&& ![string equal "" $::env($varName)]} { -	    if {![catch {mclocale [ConvertLocale $::env($varName)]}]} { +	if {[info exists env($varName)] && ("" ne $env($varName))} { +	    if {![catch { +		mclocale [ConvertLocale $env($varName)] +	    }]} {  		return  	    }  	} @@ -434,30 +520,62 @@ proc msgcat::Init {} {      #      # On Darwin, fallback to current CFLocale identifier if available.      # -    if {[string equal $::tcl_platform(os) Darwin] -	    && [string equal $::tcl_platform(platform) unix] -	    && [info exists ::tcl::mac::locale] -	    && ![string equal $::tcl::mac::locale ""]} { -	if {![catch {mclocale [ConvertLocale $::tcl::mac::locale]}]} { +    if {[info exists ::tcl::mac::locale] && $::tcl::mac::locale ne ""} { +	if {![catch { +	    mclocale [ConvertLocale $::tcl::mac::locale] +	}]} {  	    return  	}      }      # -    # 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 { ![string equal $::tcl_platform(platform) 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". +    # + +    # 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      # -    set key {HKEY_CURRENT_USER\Control Panel\International} -    if {[catch {package require registry}] \ -	    || [catch {registry get $key "locale"} locale]} { -        mclocale C +    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      }      # @@ -472,7 +590,9 @@ proc msgcat::Init {} {      variable WinRegToISO639      set locale [string tolower $locale]      while {[string length $locale]} { -        if {![catch {mclocale [ConvertLocale $WinRegToISO639($locale)]}]} { +	if {![catch { +	    mclocale [ConvertLocale [dict get $WinRegToISO639 $locale]] +	}]} {  	    return  	}  	set locale [string range $locale 1 end] | 
