Index: openacs-4/packages/acs-lang/tcl/localization-data-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/localization-data-init.tcl,v diff -u -r1.14 -r1.14.4.1 --- openacs-4/packages/acs-lang/tcl/localization-data-init.tcl 18 Aug 2003 08:02:21 -0000 1.14 +++ openacs-4/packages/acs-lang/tcl/localization-data-init.tcl 30 Sep 2004 17:42:24 -0000 1.14.4.1 @@ -64,3 +64,70 @@ nsv_set locale money:140 {$sym$sign$num} nsv_set locale money:141 {$sym$sign$num} nsv_set locale money:142 {$sym$sign$num} + +namespace eval ::lang::util { + + # Date format codes. This was brought over from lc_time_fmt, to avoid having to rebuild the + # array each time the procedure is called, which is often. + + # AG: FOR BUGFREE OPERATION it's important that variable names get + # properly delimited. This is not usually a problem because most + # of the assignments occur in square brackets where spaces are + # allowed. But it can be a problem with array values that are set + # to single variables. Example: + # + # Bad: set percent_match(Y) {$lc_time_year} + # Good: set percent_match(Y) {${lc_time_year}} + # + # The error trigger is: message catalog messages that don't have any + # whitespace between the variable name and other parts of the message. In + # this case the lc_time_fmt_compile function may return expressions where + # the variable name is appended to by the message catalog contents, + # resulting in variables that look like this: $lc_time_year\345\271\264 + # Tcl will throw an error when it encounters undefined variables. + + # Unsupported number things + set percent_match(W) "" + set percent_match(U) "" + set percent_match(u) "" + set percent_match(j) "" + + # Composites, now directly expanded, note that writing for %r specifically would be quicker than what we have here. + set percent_match(T) {[lc_leading_zeros $lc_time_hours 2]:[lc_leading_zeros $lc_time_minutes 2]:[lc_leading_zeros $lc_time_seconds 2]} + set percent_match(D) {[lc_leading_zeros $lc_time_month 2]/[lc_leading_zeros $lc_time_month 2]/[lc_leading_zeros [expr $lc_time_year%100] 2]} + set percent_match(F) {${lc_time_year}-[lc_leading_zeros $lc_time_month 2]-[lc_leading_zeros $lc_time_days 2]} + set percent_match(r) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]:[lc_leading_zeros $lc_time_minutes 2] [lc_time_name_meridian $locale $lc_time_hours]} + + # Direct Subst + set percent_match(e) {[lc_leading_space $lc_time_days]} + set percent_match(E) {[lc_leading_space $lc_time_month]} + set percent_match(f) {[lc_wrap_sunday $lc_time_day_no]} + set percent_match(Y) {${lc_time_year}} + + # Plus padding + set percent_match(d) {[lc_leading_zeros $lc_time_days 2]} + set percent_match(H) {[lc_leading_zeros $lc_time_hours 2]} + set percent_match(S) {[lc_leading_zeros $lc_time_seconds 2]} + set percent_match(m) {[lc_leading_zeros $lc_time_month 2]} + set percent_match(M) {[lc_leading_zeros $lc_time_minutes 2]} + + # Calculable values (based on assumptions above) + set percent_match(C) {[expr int($lc_time_year/100)]} + set percent_match(I) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]} + set percent_match(w) {[expr $lc_time_day_no]} + set percent_match(y) {[lc_leading_zeros [expr $lc_time_year%100] 2]} + set percent_match(Z) [lang::conn::timezone] + + # Straight (localian) lookups + set percent_match(a) {[lindex [lc_get -locale $locale "abday"] $lc_time_day_no]} + set percent_match(A) {[lindex [lc_get -locale $locale "day"] $lc_time_day_no]} + set percent_match(b) {[lindex [lc_get -locale $locale "abmon"] [expr $lc_time_month-1]]} + set percent_match(h) {[lindex [lc_get -locale $locale "abmon"] [expr $lc_time_month-1]]} + set percent_match(B) {[lindex [lc_get -locale $locale "mon"] [expr $lc_time_month-1]]} + set percent_match(p) {[lc_time_name_meridian $locale $lc_time_hours]} + + # Finally, static string replacements + set percent_match(t) {\t} + set percent_match(n) {\n} + set percent_match(%) {%} +} Index: openacs-4/packages/acs-lang/tcl/localization-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/localization-procs.tcl,v diff -u -r1.14 -r1.14.4.1 --- openacs-4/packages/acs-lang/tcl/localization-procs.tcl 1 Nov 2003 08:45:37 -0000 1.14 +++ openacs-4/packages/acs-lang/tcl/localization-procs.tcl 30 Sep 2004 17:42:25 -0000 1.14.4.1 @@ -453,95 +453,60 @@ # day_no becomes 0 for Sunday, through to 6 for Saturday. Perfect for addressing zero-based lists pulled from locale info. set lc_time_day_no [expr (($lc_time_days + $y + ($y/4) - ($y / 100) + ($y / 400)) + ((31*$m) / 12)) % 7] - - # Strange that there is no localian way to get d_t_fmt_ampm out with %wotsit - # Localian composites are dealt with in while loop below. - set to_process $fmt - # Unsupported number things - set percent_match(W) "" - set percent_match(U) "" - set percent_match(u) "" - set percent_match(j) "" - - # Composites, now directly expanded, note that writing for %r specifically would be quicker than what we have here. - set percent_match(T) {[lc_leading_zeros $lc_time_hours 2]:[lc_leading_zeros $lc_time_minutes 2]:[lc_leading_zeros $lc_time_seconds 2]} - set percent_match(D) {[lc_leading_zeros $lc_time_month 2]/[lc_leading_zeros $lc_time_month 2]/[lc_leading_zeros [expr $lc_time_year%100] 2]} - set percent_match(F) {${lc_time_year}-[lc_leading_zeros $lc_time_month 2]-[lc_leading_zeros $lc_time_days 2]} - set percent_match(r) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]:[lc_leading_zeros $lc_time_minutes 2] [lc_time_name_meridian $locale $lc_time_hours]} + return [subst [util_memoize "lc_time_fmt_compile {$fmt} $locale"]] +} - # Direct Subst - set percent_match(e) {[lc_leading_space $lc_time_days]} - set percent_match(E) {[lc_leading_space $lc_time_month]} - set percent_match(f) {[lc_wrap_sunday $lc_time_day_no]} - set percent_match(Y) {$lc_time_year} +ad_proc -public lc_time_fmt_compile { + fmt + locale +} { + Compiles ISO 14652 LC_TIME style formatting string to variable substitions and proc calls. - # Plus padding - set percent_match(d) {[lc_leading_zeros $lc_time_days 2]} - set percent_match(H) {[lc_leading_zeros $lc_time_hours 2]} - set percent_match(S) {[lc_leading_zeros $lc_time_seconds 2]} - set percent_match(m) {[lc_leading_zeros $lc_time_month 2]} - set percent_match(M) {[lc_leading_zeros $lc_time_minutes 2]} - - # Calculable values (based on assumptions above) - set percent_match(C) {[expr int($lc_time_year/100)]} - set percent_match(I) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]} - set percent_match(w) {[expr $lc_time_day_no]} - set percent_match(y) {[lc_leading_zeros [expr $lc_time_year%100] 2]} - set percent_match(Z) [lang::conn::timezone] - - # Straight (localian) lookups - set percent_match(a) {[lindex [lc_get -locale $locale "abday"] $lc_time_day_no]} - set percent_match(A) {[lindex [lc_get -locale $locale "day"] $lc_time_day_no]} - set percent_match(b) {[lindex [lc_get -locale $locale "abmon"] [expr $lc_time_month-1]]} - set percent_match(h) {[lindex [lc_get -locale $locale "abmon"] [expr $lc_time_month-1]]} - set percent_match(B) {[lindex [lc_get -locale $locale "mon"] [expr $lc_time_month-1]]} - set percent_match(p) {[lc_time_name_meridian $locale $lc_time_hours]} - - # Finally, static string replacements - set percent_match(t) {\t} - set percent_match(n) {\n} - set percent_match(%) {%} - - set transformed_string "" + @param fmt An ISO 14652 LC_TIME style formatting string. + @param locale Locale identifier must be in the locale database + @return A string that should be subst'ed in the lc_time_fmt proc + after local variables have been set. +} { + set to_process $fmt + + set compiled_string "" while {[regexp -- {^(.*?)%(.)(.*)$} $to_process match done_portion percent_modifier remaining]} { switch -exact -- $percent_modifier { x { - append transformed_string $done_portion + append compiled_string $done_portion set to_process "[lc_get -locale $locale "d_fmt"]$remaining" } X { - append transformed_string $done_portion + append compiled_string $done_portion set to_process "[lc_get -locale $locale "t_fmt"]$remaining" } c { - append transformed_string $done_portion + append compiled_string $done_portion set to_process "[lc_get -locale $locale "d_t_fmt"]$remaining" } q { - append transformed_string $done_portion + append compiled_string $done_portion set to_process "[lc_get -locale $locale "dlong_fmt"]$remaining" } Q { - append transformed_string $done_portion + append compiled_string $done_portion set to_process "[lc_get -locale $locale "dlongweekday_fmt"]$remaining" } default { - append transformed_string "${done_portion}[subst $percent_match($percent_modifier)]" + append compiled_string "${done_portion}$::lang::util::percent_match($percent_modifier)" set to_process $remaining } } } # What is left to_process must be (%.)-less, so it should be included without transformation. - append transformed_string $to_process + append compiled_string $to_process - return $transformed_string + return $compiled_string } - - ad_proc -public lc_time_utc_to_local { time_value {tz ""}