Index: openacs-4/packages/acs-lang/acs-lang.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/acs-lang.info,v diff -u -r1.6 -r1.7 --- openacs-4/packages/acs-lang/acs-lang.info 23 Sep 2002 23:32:03 -0000 1.6 +++ openacs-4/packages/acs-lang/acs-lang.info 7 Oct 2002 14:32:41 -0000 1.7 @@ -4,17 +4,17 @@ OpenACS Localization Utils OpenACS Localization Utils - f + t t - + oracle postgresql Henry Minsky OpenACS Internationalization Utilities - 2001-01-21 + 2002-09-26 ArsDigita Corporation OpenACS Internationalization Utilities. Routines for manipulating Locales, request processor hooks, templating, message catalog, and @@ -25,8 +25,8 @@ and must be run manually from a shell. See the README file in that directory for details. - + @@ -35,29 +35,31 @@ - - - + - - - - - - - - - + + + + + + + + + + + + + @@ -67,39 +69,77 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + - - - - - - - - - - - - - + Index: openacs-4/packages/acs-lang/sql/oracle/ad-locales.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/oracle/ad-locales.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/sql/oracle/ad-locales.sql 10 Jul 2002 11:57:19 -0000 1.2 +++ openacs-4/packages/acs-lang/sql/oracle/ad-locales.sql 7 Oct 2002 14:32:42 -0000 1.3 @@ -95,3 +95,13 @@ ); commit; + +create table ad_locale_user_prefs ( + user_id integer + primary key + references users (user_id), + locale varchar2(30) not null + constraint + trb_language_preference_lid_fk + references ad_locales (locale) +); Index: openacs-4/packages/acs-lang/sql/oracle/message-catalog-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/oracle/message-catalog-drop.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/sql/oracle/message-catalog-drop.sql 10 Jul 2002 11:57:19 -0000 1.2 +++ openacs-4/packages/acs-lang/sql/oracle/message-catalog-drop.sql 7 Oct 2002 14:32:42 -0000 1.3 @@ -1,7 +1,7 @@ -- -- packages/language/sql/language-drop.sql -- --- @author davis@xarg.net +-- @author davis@arsdigita.com -- @creation-date 2000-09-10 -- @cvs-id $Id$ -- Index: openacs-4/packages/acs-lang/sql/oracle/message-catalog.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/oracle/message-catalog.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/sql/oracle/message-catalog.sql 10 Jul 2002 11:57:19 -0000 1.2 +++ openacs-4/packages/acs-lang/sql/oracle/message-catalog.sql 7 Oct 2002 14:32:42 -0000 1.3 @@ -1,20 +1,40 @@ -- --- packages/acs-i18n/sql/language-create.sql +-- packages/gp-lang/sql/language-create.sql -- --- @author Jeff Davis (davis@xarg.net) +-- @author Jeff Davis (davis@arsdigita.com) +-- @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) +-- -- @creation-date 2000-09-10 -- @cvs-id $Id$ -- +create table lang_keys ( + key varchar2(200), + package_key varchar2(100) + constraint lang_keys_pk_fk + references apm_package_types (package_key) +); + create table lang_messages ( - key varchar2(200), - lang char(2) not null, - message clob, - registered_p char(1) - constraint lm_tranlated_p_tf check(registered_p in ('t','f')), - constraint lang_messages_pk primary key (key, lang) + key varchar2(200) + constraint lang_messages_key_fk + references lang_keys(key), + locale varchar2(30) + constraint lang_messages_locale_fk + references ad_locales(locale) + constraint lang_messages_locale_nn + not null, + message clob, + registered_p char(1) + constraint lm_tranlated_p_ck check(registered_p in ('t','f')), + constraint lang_messages_pk primary key (key, locale) ); +comment on table lang_messages is ' + Holds all the messages translated. The key is the way to get to a message. + This table should be read at boot time -from ACS- to load all the messages + into an nsv_array. +'; -- **************************************************************************** -- * The lang_translate_columns table holds the columns that require translation. @@ -23,26 +43,27 @@ -- **************************************************************************** create table lang_translate_columns ( - column_id integer primary key, + column_id integer + constraint ltc_column_id_pk primary key, -- cant do references on user_tables cause oracle sucks - on_which_table varchar2(50), - on_what_column varchar2(50), + on_which_table varchar2(50), + on_what_column varchar2(50), -- -- whether all entries in a column must be translated for the -- site to function. -- -- probably ultimately need something more sophisticated than -- simply required_p -- - required_p char(1) - constraint ltc_required_p_tf check(required_p in ('t','f')), + required_p char(1) + constraint ltc_required_p_ck check(required_p in ('t','f')), -- -- flag for whether to use the lang_translations table for content -- or add a row in the on_which_table table with the translated content. -- - short_p char(1) - constraint ltc_short_p_tf check(short_p in ('t','f')), - constraint ltc_u unique (on_which_table, on_what_column) + short_p char(1) + constraint ltc_short_p_ck check(short_p in ('t','f')), + constraint ltc_un unique (on_which_table, on_what_column) ); @@ -53,16 +74,15 @@ -- **************************************************************************** create table lang_translation_registry ( - on_which_table varchar(50), - on_what_id integer not null, - locale constraint ltr_locale_ref - references ad_locales(locale), + on_which_table varchar(50), + on_what_id integer + constraint ltr_on_what_id_nn not null, + locale varchar2(30) + constraint ltr_locale_fk + references ad_locales(locale), -- -- should have dependency info here -- constraint lang_translation_registry_pk primary key(on_what_id, on_which_table, locale) ); - - - Index: openacs-4/packages/acs-lang/sql/oracle/upgrade/upgrade-4.1-4.7.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/oracle/upgrade/Attic/upgrade-4.1-4.7.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/sql/oracle/upgrade/upgrade-4.1-4.7.sql 7 Oct 2002 14:32:43 -0000 1.1 @@ -0,0 +1,72 @@ +-- +-- Upgrade script from 4.1 to 4.7 +-- +-- Changes lang_messages so it uses locale instead of language +-- by looking up the default locale in ad_locales. +-- +-- There two things that could go wrong here: +-- +-- 1. There could be no locale at all for some language +-- in that case the scripts adds a new locale +-- 2. There could be no default locale +-- the script makes sure that theres is one default locale +-- pr. language +-- +-- @author Christian Hvid +-- + +-- Make sure that there is a default for every language + +UPDATE ad_locales +SET default_p = 't' +WHERE (SELECT count(*) + FROM ad_locales a + WHERE a.language = ad_locales.language AND default_p='t') = 0; + +-- Make sure that there is a locale for every language used in lang_messages + +INSERT INTO ad_locales (language, locale, country, label, nls_language, default_p) +SELECT language, + language || '_' || UPPER(language) as locale, + '??' as country, + 'Locale created by upgrade-4.1-4.7 for language ' || language as label, + '??' as nls_language, + 't' as default_p +FROM + ((SELECT DISTINCT lang as language + FROM lang_messages) MINUS + (SELECT DISTINCT language + FROM ad_locales)); + +create table temp ( + key varchar(200), + lang varchar(2), + message clob, + registered_p char(1) +); + +INSERT INTO temp(key, lang, message, registered_p) +SELECT key, lang, message, registered_p +FROM lang_messages; + +DROP TABLE lang_messages; + +create table lang_messages ( + key varchar2(200), + locale varchar2(30) + constraint lang_messages_locale_fk + references ad_locales(locale) + constraint lang_messages_locale_nn + not null, + message clob, + registered_p char(1) + constraint lm_tranlated_p_ck check(registered_p in ('t','f')), + constraint lang_messages_pk primary key (key, locale) +); + +INSERT INTO lang_messages(key, locale, message, registered_p) +SELECT key, ad_locales.locale, message, registered_p +FROM temp, ad_locales +WHERE ad_locales.language = temp.lang; + +DROP TABLE temp; Index: openacs-4/packages/acs-lang/sql/postgresql/ad-locales.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/postgresql/ad-locales.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/sql/postgresql/ad-locales.sql 10 Jul 2002 11:57:19 -0000 1.2 +++ openacs-4/packages/acs-lang/sql/postgresql/ad-locales.sql 7 Oct 2002 14:32:44 -0000 1.3 @@ -19,9 +19,11 @@ locale varchar(30) constraint ad_locale_abbrev_pk primary key, - language char(2) constraint ad_language_name_nil + language char(2) + constraint ad_language_name_nil not null, - country char(2) constraint ad_country_name_nil + country char(2) + constraint ad_country_name_nil not null, variant varchar(30), label varchar(200) @@ -51,6 +53,23 @@ nls_charset is Oracle charset name '; +create table ad_locale_user_prefs ( + user_id integer + constraint ad_locale_user_prefs_pk + primary key + constraint ad_locale_user_prefs_users_fk + references users (user_id) on delete cascade, + locale varchar(30) not null + constraint trb_language_preference_lid_fk + references ad_locales (locale) on delete cascade +); + +-- +-- +-- And now for some default locales +-- +-- + insert into ad_locales ( locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p @@ -96,3 +115,4 @@ ); end; + Index: openacs-4/packages/acs-lang/sql/postgresql/message-catalog.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/postgresql/message-catalog.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/sql/postgresql/message-catalog.sql 10 Jul 2002 11:57:19 -0000 1.2 +++ openacs-4/packages/acs-lang/sql/postgresql/message-catalog.sql 7 Oct 2002 14:32:44 -0000 1.3 @@ -9,11 +9,16 @@ begin; create table lang_messages ( - key varchar(200), - lang char(2) not null, - message text, - registered_p boolean, - constraint lang_messages_pk primary key (key, lang) + key varchar(200), + locale varchar(30) + constraint lang_messages_locale_fk + references ad_locales(locale) + constraint lang_messages_locale_nn + not null, + message text, + registered_p boolean, + constraint lang_messages_pk + primary key (key, locale) ); Index: openacs-4/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.1-4.7.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/sql/postgresql/upgrade/Attic/upgrade-4.1-4.7.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.1-4.7.sql 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,73 @@ +-- +-- Upgrade script from 4.1 to 4.7 +-- +-- Changes lang_messages so it uses locale instead of language +-- by looking up the default locale in ad_locales. +-- +-- There two things that could go wrong here: +-- +-- 1. There could be no locale at all for some language +-- in that case the scripts adds a new locale +-- 2. There could be no default locale +-- the script makes sure that theres is one default locale +-- pr. language +-- +-- @author Christian Hvid +-- + +-- Make sure that there is a default for every language + +UPDATE ad_locales +SET default_p = 't' +WHERE (SELECT count(*) + FROM ad_locales AS a + WHERE a.language = ad_locales.language AND default_p='t') = 0; + +-- Make sure that there is a locale for every language used in lang_messages + +INSERT INTO ad_locales (language, locale, country, label, nls_language, default_p) +SELECT language, + language || '_' || UPPER(language) as locale, + '??' as country, + 'Locale created by upgrade-4.1-4.7 for language ' || language as label, + '??' as nls_language, + 't' as default_p +FROM + ((SELECT DISTINCT lang as language + FROM lang_messages) EXCEPT + (SELECT DISTINCT language + FROM ad_locales)) as new_languages; + +create table temp ( + key varchar(200), + lang varchar(2), + message text, + registered_p boolean +); + +INSERT INTO temp(key, lang, message, registered_p) +SELECT key, lang, message, registered_p +FROM lang_messages; + +DROP TABLE lang_messages; + +create table lang_messages ( + key varchar(200), + locale varchar(30) + constraint lang_messages_locale_fk + references ad_locales(locale) + constraint lang_messages_locale_nn + not null, + message text, + registered_p boolean, + constraint lang_messages_pk + primary key (key, locale) +); + +INSERT INTO lang_messages(key, locale, message, registered_p) +SELECT key, ad_locales.locale, message, registered_p +FROM temp, ad_locales +WHERE cast (ad_locales.language as text) = cast (temp.lang as text) +AND ad_locales.default_p = 't'; + +DROP TABLE temp; Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/acs-lang-procs.tcl'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-lang/tcl/lang-catalog-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/Attic/lang-catalog-init.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-catalog-init.tcl 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,31 @@ +#/packages/acs-lang/tcl/lang-catalog-init.tcl +ad_library { + Loads files that contain messages. +

+ This is free software distributed under the terms of the GNU Public + License. Full text of the license is available from the GNU Project: + http://www.fsf.org/copyleft/gpl.html + + @creation-date 10 September 2000 + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @author Peter Marklund (peter@collaboraid.biz) + @author Lars Pind (lars@collaboraid.biz) + @cvs-id $Id: lang-catalog-init.tcl,v 1.1 2002/10/07 14:32:45 lars Exp $ +} + +##### +# +# Load catalog files from all packages into the database +# +##### + +# This is done in a scheduled proc so that it won't take up time at server startup. +# Instead, it can be done by a thread after the server has started multithreading. +# +# Peter Marklund, 7 October 2002: Commenting out since we don't want to source the catalog +# files on every startup (we want to source them just once). If the acs_messages table +# had a package_key column we could easily +# check if a certain package has already had its catalog files sourced or not. + +#ad_schedule_proc -once t 5 lang::catalog::load_all Index: openacs-4/packages/acs-lang/tcl/lang-catalog-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-catalog-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-catalog-procs.tcl 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,148 @@ +#/packages/acs-lang/tcl/lang-catalog-procs.tcl +ad_library { + + Routines for loading message catalog files +

+ This is free software distributed under the terms of the GNU Public + License. Full text of the license is available from the GNU Project: + http://www.fsf.org/copyleft/gpl.html + + @creation-date 10 September 2000 + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @author Peter Marklund (peter@collaboraid.biz) + @author Lars Pind (lars@collaboraid.biz) + @cvs-id $Id: lang-catalog-procs.tcl,v 1.1 2002/10/07 14:32:45 lars Exp $ +} + +namespace eval lang::catalog { + + ad_proc -public load { + {package_key "acs-lang"} + } { + Load the message catalogs from a package, defaults to /packages/acs-lang/catalog/ directory. + Catalogs specify the MIME charset name of their encoding in their pathname. + + @author Jeff Davis (davis@arsdigita.com) + @return Number of files loaded + + } { + set glob_pattern [file join [acs_package_root_dir $package_key] catalog *.cat] + ns_log Notice "Starting load of the message catalogs $glob_pattern" + + global __lang_catalog_load_package_key + set __lang_catalog_load_package_key $package_key + + set files [glob -nocomplain $glob_pattern] + + set charsets [ns_charsets] + + if {[empty_string_p $files]} { + ns_log Warning "no files found in message catalog directory" + } else { + foreach msg_file $files { + if {![regexp {/([^/]*)\.([^/]*)\.cat$} $msg_file match base msg_encoding]} { + ns_log Warning "assuming $msg_file is iso-8859-1" + set msg_encoding iso-8859-1 + } + + if {[lsearch -exact $charsets $msg_encoding] < 0} { + ns_log Warning "$msg_file in $msg_encoding not supported by tcl, assuming [encoding system]" + set msg_encoding [encoding system] + } + + ns_log Notice "Loading $msg_file in $msg_encoding" + set in [open $msg_file] + fconfigure $in -encoding [ns_encodingforcharset $msg_encoding] + set src [read $in] + close $in + + eval $src + #if {[catch {eval $src} errMsg]} { + # ns_log Warning "Failed loading message catalog $msg_file:\n$errMsg" + #} + } + } + + ns_log Notice "Finished load of the message catalog" + + unset __lang_catalog_load_package_key + + return $files + } + + ad_proc -public load_all {} { + Loops over all installed and enabled packages and invokes lang_catalog_load + for each package. + } { + db_foreach all_enabled_packages {} { + if { [file isdirectory [file join [acs_package_root_dir $package_key] catalog]] } { + lang_catalog_load $package_key + } + } + } + + ad_proc -private translate {} { + Translates all untranslated strings in a message catalog + from English into Spanish, French and German + using Babelfish. Quick way to get a multilingual site up and + running if you can live with the quality of the translations. +

+ Not a good idea to run this procedure if you have + a large message catalog. Use for testing purposes only. + + @author John Lowry (lowry@arsdigita.com) + + } { + set default_locale [parameter::get -package_id [apm_package_id_from_key acs-lang] -parameter SiteWideLocale] + db_foreach get_untranslated_messages {} { + + foreach lang [list es_ES fr_FR de_DE] { + if [catch { + set translated_message [lang_babel_translate $message en_$lang] + } errmsg] { + ns_log Notice "Error translating $message into $lang: $errmsg" + } else { + _mr $lang $key $translated_message + } + } + } + } + +} + +##### +# +# Backwards compatibility procs +# +##### + +ad_proc -deprecated -warn lang_catalog_load_all {} { + @see lang::catalog::load_all +} { + return [lang::catalog::load_all] +} + +ad_proc -deprecated -warn lang_catalog_load { + {package_key "acs-lang"} +} { + @see lang::catalog::load_all +} { + return [lang::catalog::load $package_key] +} + +ad_proc -deprecated -warn lang_translate_message_catalog {} { + Translates all untranslated strings in a message catalog + from English into Spanish, French and German + using Babelfish. Quick way to get a multilingual site up and + running if you can live with the quality of the translations. +

+ Not a good idea to run this procedure if you have + a large message catalog. Use for testing purposes only. + + @author John Lowry (lowry@arsdigita.com) + + @see lang::catalog::translate +} { + return [lang::catalog::translate] +} Index: openacs-4/packages/acs-lang/tcl/lang-catalog-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-catalog-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-catalog-procs.xql 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,28 @@ + + + + + + select package_key + from apm_package_types + where exists (select 1 + from apm_package_versions + where installed_p = 't' + and enabled_p = 't') + + + + + + select key, + message + from lang_messages lm1 + where locale = :default_locale + and not exists (select 1 + from lang_messages lm2 + where locale != :default_locale + and lm1.key = lm2.key) + + + + Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-init-oracle.xql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-init-postgresql.xql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.3 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-init.tcl'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-lang/tcl/lang-message-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/Attic/lang-message-init.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-message-init.tcl 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,22 @@ +#/packages/acs-lang/tcl/lang-message-init.tcl +ad_library { + + Initializes the message cache. +

+ This is free software distributed under the terms of the GNU Public + License. Full text of the license is available from the GNU Project: + http://www.fsf.org/copyleft/gpl.html + + @creation-date 10 September 2000 + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @author Peter Marklund (peter@collaboraid.biz) + @author Lars Pind (lars@collaboraid.biz) + @cvs-id $Id: lang-message-init.tcl,v 1.1 2002/10/07 14:32:45 lars Exp $ +} + +# +# Cache the message catalog from the database +# + +lang::message::cache Index: openacs-4/packages/acs-lang/tcl/lang-message-procs-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-message-procs-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-message-procs-oracle.xql 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,24 @@ + + + oracle8.1.6 + + + + update lang_messages + set registered_p = 't', + message = empty_clob() + where locale = :locale + and key = :key + returning message into :1 + + + + + + insert into lang_messages (key, locale, message, registered_p) + values (:key, :locale, empty_clob(), 't') + returning message into :1 + + + + Index: openacs-4/packages/acs-lang/tcl/lang-message-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-message-procs-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-message-procs-postgresql.xql 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,22 @@ + + + postgresql7.2 + + + + update lang_messages + set registered_p = 't', + message = :message + where locale = :locale + and key = :key + + + + + + insert into lang_messages (key, locale, message, registered_p) + values (:key, :locale, :message, 't') + + + + Index: openacs-4/packages/acs-lang/tcl/lang-message-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-message-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-message-procs.tcl 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,399 @@ +#/packages/acs-lang/tcl/lang-message-procs.tcl +ad_library { + + Routines for displaying web pages in multiple languages +

+ This is free software distributed under the terms of the GNU Public + License. Full text of the license is available from the GNU Project: + http://www.fsf.org/copyleft/gpl.html + + @creation-date 10 September 2000 + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @author Peter Marklund (peter@collaboraid.biz) + @author Lars Pind (lars@collaboraid.biz) + @cvs-id $Id: lang-message-procs.tcl,v 1.1 2002/10/07 14:32:45 lars Exp $ +} + +namespace eval lang::message { + + ad_proc -public register { + locale + key + message + } { + Normally accessed through the _mr procedure. + Registers a message in a given locale or language. + Inserts the message into the table lang_messages + if it does not exist and updates if it does. + + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @see _mr + + @param locale Locale or language of the message. If a language is supplied, + the default locale for the language is looked up. + Taken from ad_locales table. + @param key Unique identifier for this message. Will be the same identifier + for each language + @param message Text of the message + + } { + # First we check if the given key already exists + # or if this is different than what we have saved. + + # Check if the $lang parameter is a language or a locale + if { [string length $locale] == 2 } { + # It seems to be a language (iso codes are 2 characters) + # We don't do a more throughout check since this is not + # invoked by users. + # let's get the default locale for that language + set locale [util_memoize [list ad_locale_locale_from_lang $locale]] + } + + # Check the cache + if { [nsv_exists lang_message_$locale $key] } { + + set old_message [nsv_get lang_message_$locale $key] + + if { ![string equal $message $old_message] } { + + # changed message ... update. + + # Trying to avoid hitting Oracle bug#2011927 + + if { [empty_string_p [string trim $message]] } { + db_dml lang_message_null_update {} + } else { + db_dml lang_message_update {} -clobs [list $message] + } + nsv_set lang_message_$locale $key $message + } + } else { + ns_log Notice "Inserting into database message: $locale $key" + db_transaction { + # As above, avoiding the bug#2011927 from Oracle. + + if { [empty_string_p [string trim $message]] } { + db_dml lang_message_insert_null_msg {} + } else { + # LARS: + # We may need to have two different lines here, one for + # Oracle w/clobs, one for PG w/o clobs. + db_dml lang_message_insert {} -clobs [list $message] + } + nsv_set lang_message_$locale $key $message + } + } + } + + ad_proc -public lookup { + locale + key + {default "TRANSLATION MISSING"} + } { + Normally accessed through the _ procedure. + + Returns a translated string for the given language and message key. + + The key of the localized message is stored in the following format, + string1.string2 where string1 is a string that contains only alpha + characters and '-' concateneted with a '.' and string2 is the + identification of the message. + + The lookup is tried in this order: + + 1 A check is done by prefixing the key with + the package key of the request. + 2. If there is no match, a lookup is performed with the key + prepended with 'generic.' since it doesn't contain a dot. + 3. If there is no match a check is done with the full key and + a warning is issued if a match is found since this means the key is uncategorized. + All keys should belong to a package or be generic/site-wide. + 4. If there is still no match the default message is issued. + + @author Jeff Davis (davis@arsdigita.com), Henry Minsky (hqm@arsdigita.com) + @author Bruno Mattarollo + @author Peter Marklund (peter@collaboraid.biz) + @see _ + + @param locale Locale (e.g., "en_US") or language (e.g., "en") string. + @param key Unique identifier for this message. Will be the same identifier + for each language + @return The translated string for the message specified by the key in the language specified. + } { + # Peter Marklund: I simplified this proc by removing the check for a dot + # We could add that check back later for optimization but there was too much + # duplication in the proc and it was too complex + # TODO: add translation links + + set full_key $key + set default_locale [parameter::get -package_id [apm_package_id_from_key acs-lang] -parameter SiteWideLocale] + + if { [string length $locale] == 2 } { + + # it's a language and not a locale + # let's get the default locale for this language + # The cache is flushed if the default locale for this language is + # is changed. + set locale [util_memoize [list ad_locale_locale_from_lang $locale]] + + } + + # Since we have for sure the locale (one way or another) + set lang [string range $locale 0 1] + + # Most keys should be prefixed with the package key so try that first + if { [catch "set package_key \[ad_conn package_key\].${full_key}" errmsg] } { + # This means we have no connection and no package_key to use + set package_key $full_key + } + + set generic_key "generic.${full_key}" + + if { [nsv_exists lang_message_$locale $package_key] } { + # Prefixing with package key + + return [nsv_get lang_message_$locale $package_key] + + } elseif { [nsv_exists lang_message_$locale $generic_key] } { + # Prefixing with generic + + # We found it. + return [nsv_get lang_message_$locale $generic_key] + + } elseif { [nsv_exists lang_message_$locale $full_key] } { + + if {! [regexp {[\.]} $full_key match] } { + ns_log Warning "Warning" "Localized message key \"$full_key\" found but is not categorized (contains no dot)." + } + + return [nsv_get lang_message_$locale $full_key] + + } else { + + # Oops. No, not here ... Let's get the translation missing + # message out! If we are being queried in the default locale + # then we can give the answer right away, if not, requery + # ourselves with the default locale (this is the default + # behaviour required). + + if {[string match $locale $default_locale]} { + + if {![empty_string_p $default]} { + + if { [string equal $default "TRANSLATION MISSING"] } { + + append default_answer $default " - " $full_key + + } else { + + set default_answer $default + + } + + return $default_answer + + } else { + + return "$key" + + } + + } else { + + # Returning the default (in the default locale) + #return "[lang_message_lookup $default_locale $key $default]" + + # Peter: Just return the default + return $default + } + } + } + + ad_proc -private translate { + msg + locale + } { + Translates an English string into a different language + using Babelfish. + + @author Henry Minsky (hqm@mit.edu) + + @param msg String to translate + @param lang Abbreviation for lang in which to translate string + @return Translated string + } { + set lang [string range $locale 0 2] + set marker "XXYYZZXX. " + set qmsg "$marker $msg" + set url "http://babel.altavista.com/translate.dyn?doit=done&BabelFishFrontPage=yes&bblType=urltext&url=" + set babel_result [ns_httpget "$url&lp=$lang&urltext=[ns_urlencode $qmsg]"] + set result_pattern "$marker (\[^<\]*)" + if [regexp -nocase $result_pattern $babel_result ignore msg_tr] { + regsub "$marker." $msg_tr "" msg_tr + return [string trim $msg_tr] + } else { + error "Babelfish translation error" + } + } + + + ad_proc -private cache {} { + Loads the entire message catalog from the database into the cache. + } { + # We segregate messages by language. It might reduce contention + # if we segregage instead by package. Check for problems with ns_info locks. + + set i 0 + db_foreach select_locale_keys {} { + nsv_set lang_message_$locale $key $message + incr i + } + + db_release_unused_handles + + ns_log Notice "Initialized message table; got $i rows" + } + +} + + + +##### +# +# Shorthand notation procs _ and _mr +# +##### + +ad_proc -public _mr { locale key message } { + + Registers a message in a given locale or language. + Inserts the message into the table lang_messages + if it does not exist and updates if it does. + + @author Jeff Davis (davis@arsdigita.com) + + @param locale Abbreviation for language of the message or the locale. + @param key Unique identifier for this message. Will be the same identifier + for each language + @param message Text of the message + + @see lang::message::register +} { + return [lang::message::register $locale $key $message] +} + + +ad_proc -public _ { + locale + key + {default "TRANSLATION MISSING"} +} { + Returns a translated string for the given language and message key. + If the user is a translator, inserts tags to link to the translator + interface. This allows a translator to work from the context of a web page. + + @author Jeff Davis (davis@arsdigita.com) + + @param locale Locale or language of the message. Locale is taken from ad_locales table, + language is taken from language_codes table. + @param key Unique identifier for this message. Will be the same identifier + for each locale + @return The translated string for the message specified by the key in the language specified. + + @see lang::message::lookup +} { + return [lang::message::lookup $locale $key $default] +} + + + + +##### +# +# Backwards compatibility procs +# +##### + +ad_proc -private -deprecated -warn lang_message_register { locale key message } { + + Normally accessed through the _mr procedure. + Registers a message in a given locale or language. + Inserts the message into the table lang_messages + if it does not exist and updates if it does. + + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @see _mr + + @param locale Locale or language of the message. If a language is supplied, + the default locale for the language is looked up. + Taken from ad_locales table. + @param key Unique identifier for this message. Will be the same identifier + for each language + @param message Text of the message + + @see lang::message::register +} { + return [lang::message::register $locale $key $message] +} + +ad_proc -private -deprecated -warn lang_message_lookup { + locale + key + {default "TRANSLATION MISSING"} +} { + Normally accessed through the _ procedure. + + Returns a translated string for the given language and message key. + + The key of the localized message is stored in the following format, + string1.string2 where string1 is a string that contains only alpha + characters and '-' concateneted with a '.' and string2 is the + identification of the message. + + The lookup is tried in this order: + + 1 A check is done by prefixing the key with + the package key of the request. + 2. If there is no match, a lookup is performed with the key + prepended with 'generic.' since it doesn't contain a dot. + 3. If there is no match a check is done with the full key and + a warning is issued if a match is found since this means the key is uncategorized. + All keys should belong to a package or be generic/site-wide. + 4. If there is still no match the default message is issued. + + @author Jeff Davis (davis@arsdigita.com), Henry Minsky (hqm@arsdigita.com) + @author Bruno Mattarollo + @author Peter Marklund (peter@collaboraid.biz) + @see _ + + @param locale Locale (e.g., "en_US") or language (e.g., "en") string. + @param key Unique identifier for this message. Will be the same identifier + for each language + @return The translated string for the message specified by the key in the language specified. + + @see lang::message::lookup +} { + return [lang::message::lookup $locale $key $default] +} + +ad_proc -deprecated -warn lang_babel_translate { + msg + lang +} { + Translates an English string into a different language + using Babelfish. + + @author Henry Minsky (hqm@mit.edu) + + @param msg String to translate + @param lang Abbreviation for lang in which to translate string + @return Translated string + + @see lang::message::translate +} { + return [lang::message::translate $msg $lang] +} + Index: openacs-4/packages/acs-lang/tcl/lang-message-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-message-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-message-procs.xql 7 Oct 2002 14:32:45 -0000 1.1 @@ -0,0 +1,29 @@ + + + + + + update lang_messages + set registered_p = 't', + message = null + where locale = :locale + and key = :key + + + + + + insert into lang_messages (key, locale, message, registered_p) + values (:key, :locale, null, 't') + + + + + + select locale, key, message + from lang_messages + where registered_p = 't' + + + + Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-procs-oracle.xql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.4 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-procs.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/lang-procs.xql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-lang/tcl/lang-util-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/Attic/lang-util-procs-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-util-procs-postgresql.xql 7 Oct 2002 14:32:46 -0000 1.1 @@ -0,0 +1,17 @@ + + + + postgresql7.1 + + + + + select nls_language + from ad_locales + where language = :language + limit 1 + + + + + Index: openacs-4/packages/acs-lang/tcl/lang-util-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-util-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-util-procs.tcl 7 Oct 2002 14:32:46 -0000 1.1 @@ -0,0 +1,443 @@ +#/packages/acs-lang/tcl/lang-util-procs.tcl +ad_library { + + Utility routines for translating pages. Many of these procs deal with + message keys embedded in strings with the #key# or the <#key text#> syntax. +

+ This is free software distributed under the terms of the GNU Public + License. Full text of the license is available from the GNU Project: + http://www.fsf.org/copyleft/gpl.html + + @creation-date 10 September 2000 + @author Jeff Davis (davis@arsdigita.com) + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) + @author Peter Marklund (peter@collaboraid.biz) + @author Lars Pind (lars@collaboraid.biz) + @cvs-id $Id: lang-util-procs.tcl,v 1.1 2002/10/07 14:32:46 lars Exp $ +} + +namespace eval lang::util { + + ad_proc -public lang_sort { + field + {locale {}} + } { + Each locale can have a different alphabetical sort order. You can test + this proc with the following data: +

+        insert into lang_testsort values ('lama');
+        insert into lang_testsort values ('lhasa');
+        insert into lang_testsort values ('llama');
+        insert into lang_testsort values ('lzim');  
+        
+ + @author Jeff Davis (davis@arsdigita.com) + + @param field Name of Oracle column + @param locale Locale for sorting. + If locale is unspecified just return the column name + @return Language aware version of field for Oracle ORDER BY clause. + + } { + # Use west european for english since I think that will fold + # cedilla etc into reasonable values... + set lang(en) "XWest_european" + set lang(de) "XGerman_din" + set lang(fr) "XFrench" + set lang(es) "XSpanish" + + if { [empty_string_p $locale] || ![info exists lang($locale)] } { + return $field + } else { + return "NLSSORT($field,'NLS_SORT = $lang($locale)')" + } + } + + ad_proc -private get_hash_indices { multilingual_string } { + Returns a list of two element lists containing + the start and end indices of a #message_key# match in the multilingual string. + This proc is used by the localize proc. + + @author Peter marklund (peter@collaboraid.biz) + } { + + set regexp_pattern {(?:^|[^\\])(\#[-a-zA-Z0-9_:\.]+\#)} + return [get_regexp_indices $multilingual_string $regexp_pattern] + } + + ad_proc get_adp_message_regexp_pattern {} { + The regexp expression used by proc get_adp_message_indices and elsewhere + to extract temporary message catalog tags (<#...#>) from adp templates. + The first sub match of the expression is the whole tag, the second sub match + is the message key, and the third sub match is the message text in en_US locale. + + @author Peter marklund (peter@collaboraid.biz) + } { + return {(<#\s*?([-a-zA-Z0-9_:\.]+)\s+([^<]+)#>)} + } + + ad_proc get_adp_message_indices { adp_file_string } { + Given the contents of an adp file return the indices of the + start and end chars of embedded message keys on the syntax: + + <#package_key.message_key Some en_US text#> + + @author Peter marklund (peter@collaboraid.biz) + } { + return [lang::util::get_regexp_indices $adp_file_string [get_adp_message_regexp_pattern]] + } + + ad_proc -private get_regexp_indices { multilingual_string regexp_pattern } { + Returns a list of two element lists containing + the start and end indices of what is captured by the first parenthesis in the + given regexp pattern in the multilingual string. The + regexp pattern must follow the syntax of the expression argument to the TCL regexp command. + It must also contain exactly one capturing parenthesis for the pieces of text that indices + are to be returned for. + + @see get_hash_indices + + @author Peter marklund (peter@collaboraid.biz) + } { + + set multilingual_string_offset "0" + set offset_string $multilingual_string + set indices_list [list] + + while { [regexp -indices $regexp_pattern $offset_string full_match_idx key_match_idx] } { + + set start_idx [lindex $key_match_idx 0] + set end_idx [lindex $key_match_idx 1] + + lappend indices_list [list [expr $multilingual_string_offset + $start_idx] \ + [expr $multilingual_string_offset + $end_idx]] + + set new_offset [expr $end_idx + 1] + set multilingual_string_offset [expr $multilingual_string_offset + $new_offset] + set offset_string [string range $offset_string $new_offset end] + } + + return $indices_list + } + + ad_proc extract_keys_from_adps { adp_files } { + Modify the given adp templates by replacing occurencies of + + <#package_key.message_key Some en_US text#> + + with #package_key.message_key# and create entries in the file + $package_root/catalog/$package_key.en_US.iso-8859-1.cat for + each of these keys. + + @author Peter marklund (peter@collaboraid.biz) + } { + + # First open the catalog file of the package to add new message keys to + if { [llength $adp_files] > 0 } { + set adp_file [lindex $adp_files 0] + + # Open the corresponding catalog file of the package for writing + # Create the catalog directory if it doesn't exist + regexp {^packages/([^/]+)} $adp_file full_match package_key + set catalog_dir "[acs_root_dir]/packages/$package_key/catalog" + if { ![file isdirectory $catalog_dir] } { + ns_log Notice "lang_extract_keys_from_adps: Creating new catalog directory $catalog_dir" + file mkdir $catalog_dir + } + set catalog_file_path "$catalog_dir/$package_key.en_US.iso-8859-1.cat" + ns_log Notice "lang_extract_keys_from_adps: opening catalog file $catalog_file_path for writing" + set catalog_file_id [open "$catalog_file_path" a+] + # The file may not end in a new line so add one + puts $catalog_file_id "\n" + } else { + # No files to process so return + return + } + + # Use the original catalog file contents to determine if a key should + # be added to the catalog file or not + set original_catalog_file_contents [read $catalog_file_id] + + # Keep track of the messages added to the catalog file + array set added_catalog_messages {} + + # Loop over and process the adp files + foreach adp_file $adp_files { + + # We keep track of when we've written to the catalog file to be able + # to add a comment for each adp + set has_written_to_catalog_file_p "0" + + set full_adp_path "[acs_root_dir]/$adp_file" + ns_log Notice "processing adp file $full_adp_path" + + # Make a backup of the adp file first + # Do not overwrite old backup files + if { [catch "file copy $full_adp_path \"${full_adp_path}.orig\"" errmsg] } { + ns_log Warning "The file $full_adp_path could not be backed up before message key extraction since backup file ${full_adp_path}.orig already exists" + } + + # Read the contents of the adp file + set file_contents [template::util::read_file $full_adp_path] + set modified_file_contents $file_contents + + # Loop over each message tag in the adp + # Get the indices of the first and last char of the <#...#> text snippets + set message_key_indices [lang::util::get_adp_message_indices $file_contents] + foreach index_pair $message_key_indices { + + set tag_start_idx [lindex $index_pair 0] + set tag_end_idx [lindex $index_pair 1] + set message_tag "[string range $file_contents $tag_start_idx $tag_end_idx]" + + # Extract the message key and the text from the message tag + # The regexp on the message tag string should never fail as the message tag + # was extracted with a known regexp + if { ![regexp [lang::util::get_adp_message_regexp_pattern] $message_tag full_match message_tag message_key new_en_us_text] } { + ns_log Error "Internal programming error: could not extract message key and text from the message tag $message_tag in file $adp_file. This means there is a mismatch with the regexp that extracted the message key." + continue + } + + # If the message key doesn't contain the package key prefix then add such a prefix + if { ![regexp {\.} $message_key match] } { + set message_key "${package_key}.${message_key}" + } + + # Make the key unique so that we can add it to the catalog file + set message_key_to_add [get_unique_key_to_add_to_catalog_file $original_catalog_file_contents [array get added_catalog_messages] $message_key $new_en_us_text] + if { ![empty_string_p $message_key_to_add] } { + if { ![string equal $message_key_to_add $message_key] } { + # The message key had to be changed to be made unique + ns_log Warning "The message key $message_key was changed to $message_key_to_add to be made unique. If the value was mistyped and should have been the same as previously then you must manually remove the entry for $message_key_to_add from the catalog file and change the key in the adp $adp_file fom $message_key_to_add to $message_key" + } + + set message_key $message_key_to_add + ns_log Notice "adding message key $message_key to catalog file" + + if { !$has_written_to_catalog_file_p } { + # Show which template the keys are for + puts $catalog_file_id "# $adp_file" + } + + puts $catalog_file_id "_mr en_US $message_key \{${new_en_us_text}\}" + set added_catalog_messages($message_key) "$new_en_us_text" + set has_written_to_catalog_file_p "1" + } else { + ns_log Notice "message key $message_key already exists in catalog file with same value, not adding" + } + + # Insert new or update existing message key + lang::message::register "en_US" $message_key $new_en_us_text + + + # Replace the message tag with the message key + regsub [lang::util::get_adp_message_regexp_pattern] $modified_file_contents "#${message_key}#" modified_file_contents + } + + # Update the adp with the replaced message keys + set adp_file_id [open $full_adp_path w] + puts $adp_file_id "$modified_file_contents" + close $adp_file_id + } + + # Close the catalog file + if { [info exists catalog_file_id] } { + close $catalog_file_id + } + } + + ad_proc -private get_unique_key_to_add_to_catalog_file { + original_catalog_file_contents + added_catalog_messages + message_key + new_en_us_text + } { + Returns a unique message key that can be added to the given catalog file + contents. If the message key is already in the file with the same value then + an empty string is returned indicating that no insertion is needed. If the + key already exists in the file with a different value then the key returned + will have an integer appended to it to make it unique. + + @author Peter marklund (peter@collaboraid.biz) + } { + + # Get any existing message from original catalog file + regexp "_mr\\s+\\S+\\s+${message_key}\\s+\{(\[^\}\]+)\}" $original_catalog_file_contents match existing_en_us_text + + # See if we already inserted the message + array set added_messages_array $added_catalog_messages + if { ![info exists existing_en_us_text] } { + set existing_en_us_text [lindex [array get added_messages_array $message_key] 1] + } + + if { [info exists existing_en_us_text] && ![empty_string_p $existing_en_us_text] } { + + # The key already exists in the catalog file, check if the values are the same + if { [string equal $new_en_us_text $existing_en_us_text] } { + # Value is the same, no need to change the catalog file + set add_key_to_catalog_file_p "0" + } else { + # Value is different. Assume that the new text is correct but that the + # key needs to be changed to be unique + set unique_message_key "${message_key}_2" + + set message_key_to_add [get_unique_key_to_add_to_catalog_file $original_catalog_file_contents [array get added_messages_array] $unique_message_key $new_en_us_text] + + return $message_key_to_add + } + + } else { + # The message key is not already in the catalog file so add it + set add_key_to_catalog_file_p "1" + } + + if { $add_key_to_catalog_file_p } { + + return $message_key + } else { + # No key should be added to catalog file + return "" + } + } + + ad_proc -public localize { + string_with_hashes + } { + Takes a string with embedded message keys on the format #message_key_name# + and returns the same string but with the message keys (and their surrounding hash + marks) replaced with the corresponding value in the message catalog. Message lookup + is done with the locale of the request. If message lookup fails for a certain key + then that key is not replaced. + + @author Peter marklund (peter@collaboraid.biz) + } { + set indices_list [get_hash_indices $string_with_hashes] + + set subst_string $string_with_hashes + foreach item_idx $indices_list { + # The replacement string starts and ends with a hash mark + set replacement_string [string range $string_with_hashes [lindex $item_idx 0] \ + [lindex $item_idx 1]] + set message_key [string range $replacement_string 1 [expr [string length $replacement_string] - 2]] + + # Attempt a message lookup + set message_value [_ [ad_locale request locale] $message_key "not_found"] + + # Do substitution if message lookup succeeded + if { ![string equal $message_value "not_found"] } { + regsub $replacement_string $subst_string $message_value subst_string + } + } + + return $subst_string + } + + ad_proc -public charset_for_locale { + locale + } { + Returns the MIME charset name corresponding to a locale. + + @author Henry Minsky (hqm@mit.edu) + @param locale Name of a locale, as language_COUNTRY using ISO 639 and ISO 3166 + @return IANA MIME character set name + } { + return [db_string charset_for_locale {}] + } + + ad_proc -public default_locale_from_lang { + language + } { + Returns the default locale for a language + + @author Henry Minsky (hqm@mit.edu) + @param language Name of a country, using ISO-3166 two letter code + @return Default locale + } { + return [db_string default_locale_from_lang {}] + } + + ad_proc -public nls_language_from_language { + language + } { + Returns the nls_language name for a language + + @author Henry Minsky (hqm@mit.edu) + @param language Name of a country, using ISO-3166 two letter code + @return The nls_language name of the language. + } { + return [db_string nls_language_from_language {}] + } + + +} + +##### +# +# Compatibility procs +# +##### + +ad_proc -deprecated -warn lang_sort { + field + {locale {}} +} { + Each locale can have a different alphabetical sort order. You can test + this proc with the following data: +
+    insert into lang_testsort values ('lama');
+    insert into lang_testsort values ('lhasa');
+    insert into lang_testsort values ('llama');
+    insert into lang_testsort values ('lzim');  
+    
+ + @author Jeff Davis (davis@arsdigita.com) + + @param field Name of Oracle column + @param locale Locale for sorting. + If locale is unspecified just return the column name + @return Language aware version of field for Oracle ORDER BY clause. + + @see lang::util::sort +} { + return [lang::util::sort $field $locale] +} + +ad_proc -deprecated -warn ad_locale_charset_for_locale { + locale +} { + Returns the MIME charset name corresponding to a locale. + + @see ad_locale + @author Henry Minsky (hqm@mit.edu) + @param locale Name of a locale, as language_COUNTRY using ISO 639 and ISO 3166 + @return IANA MIME character set name + @see lang::util::charset_for_locale +} { + return [lang::util::charset_for_locale $locale] +} + +ad_proc -deprecated -warn ad_locale_locale_from_lang { + language +} { + Returns the default locale for a language + + @author Henry Minsky (hqm@mit.edu) + @param language Name of a country, using ISO-3166 two letter code + @return Default locale + @see lang::util::default_locale_from_lang +} { + return [lang::util::default_locale_from_lang $language] +} + +ad_proc -deprecated -warn ad_locale_language_name { + language +} { + Returns the nls_language name for a language + + @author Henry Minsky (hqm@mit.edu) + @param language Name of a country, using ISO-3166 two letter code + @return The nls_language name of the language. + @see lang::util::nls_language_from_language +} { + return [lang::util::nls_language_from_language $language] +} Index: openacs-4/packages/acs-lang/tcl/lang-util-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/lang-util-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-lang/tcl/lang-util-procs.xql 7 Oct 2002 14:32:46 -0000 1.1 @@ -0,0 +1,25 @@ + + + + + + + select mime_charset + from ad_locales + where locale = :locale + + + + + + + + select locale + from ad_locales + where language = :language + and default_p = 't' + + + + + Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-lang/tcl/locale-init.tcl'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-lang/tcl/locale-procs-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/Attic/locale-procs-oracle.xql,v diff -u -r1.1 -r1.2 --- openacs-4/packages/acs-lang/tcl/locale-procs-oracle.xql 2 May 2001 20:15:34 -0000 1.1 +++ openacs-4/packages/acs-lang/tcl/locale-procs-oracle.xql 7 Oct 2002 14:32:46 -0000 1.2 @@ -3,14 +3,12 @@ oracle8.1.6 - + - select ( (sysdate - timezone.local_to_utc (:system_timezone, sysdate)) * 24 ) - from dual + select ( (sysdate - timezone.local_to_utc (:system_timezone, sysdate)) * 24 ) from dual - - + Index: openacs-4/packages/acs-lang/tcl/locale-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/Attic/locale-procs-postgresql.xql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/tcl/locale-procs-postgresql.xql 4 May 2001 19:29:07 -0000 1.2 +++ openacs-4/packages/acs-lang/tcl/locale-procs-postgresql.xql 7 Oct 2002 14:32:46 -0000 1.3 @@ -3,14 +3,12 @@ postgresql7.1 - + select ( (current_time - timezone__local_to_utc (:system_timezone, current_time)) * 24 ) - - - + Index: openacs-4/packages/acs-lang/tcl/locale-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/locale-procs.tcl,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-lang/tcl/locale-procs.tcl 29 Aug 2001 21:22:49 -0000 1.2 +++ openacs-4/packages/acs-lang/tcl/locale-procs.tcl 7 Oct 2002 14:32:46 -0000 1.3 @@ -9,44 +9,259 @@ @creation-date 28 September 2000 @author Henry Minsky (hqm@mit.edu) + @author Lars Pind (lars@pinds.com) @cvs-id $Id$ } +namespace eval lang::system { -ad_proc -public ad_locale_set_system_timezone { timezone } { Tell OpenACS -what timezone Oracle thinks it is running in. + ad_proc -public locale { + {-package_id ""} + {-site_wide:boolean} + } { + Get system locale setting for a given package instance. + + @param package_id The package for which you want to get the locale setting. + @param site_wide Set this if you want to get the site-wide locale setting. + } { + if { $site_wide_p } { + set package_id [apm_package_id_from_key "acs-lang"] + return [parameter::get -package_id $package_id -parameter SiteWideLocale] + } - @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) -} { - set pid [apm_package_id_from_key "acs-lang"] - ad_parameter -set $timezone -package_id $pid SystemTimezone acs-lang 0 -} + if { [empty_string_p $package_id] } { + set package_id [ad_conn package_id] + } + # Pssst! We don't actually use this package thing, + # but we'll probably do so later. + set locale {} -ad_proc -public ad_locale_get_system_timezone { } { Ask OpenACS -what it thinks Oracle's timezone is. + # If there's no package setting, use the site-wide setting + if { [empty_string_p $locale] } { + set locale [locale -site_wide] + } + return $locale + } - @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) -} { - set pid [apm_package_id_from_key "acs-lang"] - return [ad_parameter -package_id $pid SystemTimezone acs-lang 0] + ad_proc -public set_locale { + {-package_id ""} + {-site_wide:boolean} + locale + } { + Set system locale setting for a given package instance, or the + site-wide system locale. + + @param package_id The package for which you want to set the locale setting. + @param site_wide Set this if you want to set the site-wide locale setting. + @param locale The new locale that you want to use as your system locale. + } { + if { $site_wide_p } { + set package_id [apm_package_id_from_key "acs-lang"] + parameter::set_value -package_id $package_id -parameter SiteWideLocale -value $locale + } else { + if { [empty_string_p $package_id] } { + set package_id [ad_conn package_id] + } + # Pssst! We don't actually use this package thing, + # but we'll probably do so later. + set_locale -site_wide $locale + } + } + + ad_proc -public language { + {-package_id ""} + {-site_wide:boolean} + } { + Get system language setting for a given package instance. + + @param package_id The package for which you want to get the language setting. + @param site_wide Set this if you want to get the site-wide language setting. + } { + return [string range [locale -package_id $package_id -site_wide=$site_wide_p] 0 1] + } + + ad_proc -public timezone {} { + Ask OpenACS what it thinks our timezone is. + + @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + } { + set package_id [apm_package_id_from_key "acs-lang"] + return [parameter::get -package_id $package_id -parameter SystemTimezone -default 0] + } + + ad_proc -public set_timezone { + timezone + } { + Tell OpenACS what timezone we think it's running in. + + @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + } { + set package_id [apm_package_id_from_key "acs-lang"] + parameter::set_value -package_id $package_id -parameter SystemTimezone -value $timezone + } + + ad_proc -public timezone_utc_offset { } { + @return number of hours to subtract from local (database) time to get UTC + } { + set system_timezone [timezone] + return [db_string system_utc_offset {}] + } + } +namespace eval lang::user { -ad_proc -public ad_locale_system_tz_offset { } { - @return number of hours to subtract from local (Oracle) time to get UTC -} { - set system_timezone [ad_locale_get_system_timezone] - return [db_string system_offset { - select ( (sysdate - timezone.local_to_utc (:system_timezone, sysdate)) * 24 ) - from dual - }] + ad_proc -public locale { + {-package_id ""} + {-site_wide:boolean} + } { + Get user locale preference for a given package instance. + This preliminary implementation only has one site-wide setting, though. + + @param package_id The package for which you want to get the locale preference. + @param site_wide Set this if you want to get the site-wide locale preference. + } { + set user_id [ad_conn user_id] + if { $user_id == 0 } { + return "" + } + + # Pssst! We don't actually use this package thing, + # but we'll probably do so later. + if { $site_wide_p } { + + set package_id [apm_package_id_from_key "acs-lang"] + return [db_string get_user_locale {} -default ""] + + } elseif { [empty_string_p $package_id] } { + set package_id [ad_conn package_id] + } + set locale [db_string get_user_locale {} -default ""] + + # If there's no package setting, use the site-wide setting + if { [empty_string_p $locale] } { + set locale [locale -site_wide] + } + return $locale + } + + ad_proc -public set_locale { + {-package_id ""} + {-site_wide:boolean} + locale + } { + Set system locale setting for a given package instance. + This preliminary implementation only has one site-wide setting, though. + + @param package_id The package for which you want to set the locale setting. + @param site_wide Set this if you want to set the site-wide locale setting. + @param locale The new locale that you want to use as your system locale. + } { + set user_id [ad_conn user_id] + if { $user_id == 0 } { + return + } + + # Pssst! We don't actually use this package thing, + # but we'll probably do so later. + if { $site_wide_p } { + set package_id [apm_package_id_from_key "acs-lang"] + } elseif { [empty_string_p $package_id] } { + set package_id [ad_conn package_id] + } + + set user_locale_exists_p [db_string user_locale_exists_p {}] + if { $user_locale_exists_p } { + db_dml update_user_locale {} + } else { + db_dml insert_user_locale {} + } + } + + ad_proc -public language { + {-package_id ""} + {-site_wide:boolean} + } { + Get user language preference for a given package instance. + This preliminary implementation only has one site-wide setting, though. + + @param package_id The package for which you want to get the language setting. + @param site_wide Set this if you want to get the site-wide language setting. + } { + return [string range [locale -package_id $package_id -site_wide=$site_wide_p] 0 1] + } + + ad_proc -public timezone {} { + Get the user's timezone. Defaults to system timezone if the user has no setting. + + @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + } { + # We probably don't want to keep this in client properties, since these are + # no longer permanent. We'll move this into a DB table at some point. + set timezone [ad_get_client_property -cache t "acs-lang" "timezone"] + if { [empty_string_p $timezone] } { + # No user timezone, return the system timezone + set timezone [parameter::get -parameter DefaultTimezone -package_id [apm_package_id_from_key acs-lang] -default "PST"] + } + return $timezone + } + + ad_proc -public set_timezone { + timezone + } { + Set the user's timezone setting. + + @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + } { + ad_set_client_property -persistent t "acs-lang" timezone $timezone + } + } +namespace eval lang::conn { + ad_proc -public locale { + {-package_id ""} + {-site_wide:boolean} + } { + Get the locale for this request, perhaps for a given package instance. + + @param package_id The package for which you want to get the locale. + @param site_wide Set this if you want to get the site-wide locale. + } { + set locale [lang::user::locale -package_id $package_id -site_wide=$site_wide_p] + if { [empty_string_p $locale] } { + set locale [lang::system::locale -package_id $package_id -site_wide=$site_wide_p] + } + return $locale + } -ad_proc -public ad_locale {context item} { + ad_proc -public language { + {-package_id ""} + {-site_wide:boolean} + } { + Get the language for this request, perhaps for a given package instance. + + @param package_id The package for which you want to get the language. + @param site_wide Set this if you want to get the site-wide language. + } { + return [string range [locale -package_id $package_id -site_wide=$site_wide_p] 0 1] + } + +} + +##### +# +# Backwards compatibility procs +# +##### + +ad_proc -deprecated -warn ad_locale { + context + item +} { Returns the value of a locale item in a particular context. For example, to get the language, locale, and timezone preference for the current user: @@ -78,120 +293,111 @@ You can change the implementation to add other items as required. @return Value of the item in the specified context + @see lang::conn::locale + @see lang::user::locale + @see lang::user::language + @see lang::user::timezone + @see lang::util::charset_for_locale } { switch $context { + request { + return [lang::conn::locale -site_wide] + } user { - set locale [ad_get_client_property -cache t "acs-lang" locale] - if {[empty_string_p $locale]} { - set locale [ad_parameter DefaultLocale acs-lang "en_US"] - ad_locale_set locale $locale - ad_locale_set lang [string range $locale 0 1] - ad_locale_set timezone [ad_parameter DefaultTimezone acs-lang "PST"] - } switch $item { locale { - return $locale + return [lang::user::locale -site_wide] } language { - return [string range $locale 0 1] + return [lang::user::language -site_wide] } timezone { - return [ad_get_client_property -cache t "acs-lang" "timezone"] + return [lang::user::timezone] } default { error "unsupported option to ad_locale: $item" } } } - subsite { - error "ad_locale: subsite context not yet implemented" - } charset { - return [ad_locale_charset_for_locale $item] + return [lang::util::charset_for_locale $item] } - fromabbrev { - return [ad_locale_locale_from_abbrev $item] - } default { error "ad_locale: unknown context $context" } } } -ad_proc -public ad_locale_set { item value } { +ad_proc -deprecated -warn ad_locale_set { + item + value +} { Sets the user's preferred locale info as a session var

usage:

     ad_locale_set locale "en_US"
     ad_locale_set timezone "PST"
     
+ @see lang::user::set_locale + @see lang::user::set_timezone } { - set user_id [ad_get_user_id] - ad_set_client_property -persistent t "acs-lang" $item $value + switch $item { + locale { + lang::user::set_locale -site_wide $value + } + timezone { + lang::user::set_timezone $value + } + default { + error "Unknown item, $item" + } + } } -ad_proc -public ad_locale_charset_for_locale { locale } { - - Returns the MIME charset name corresponding to a locale. - - @see ad_locale - @author Henry Minsky (hqm@mit.edu) +ad_proc -deprecated -warn ad_locale_set_system_timezone { + timezone +} { + Tell OpenACS what timezone we think it's running in. - @param locale Name of a locale, as language_COUNTRY using ISO 639 and ISO 3166 - - @return IANA MIME character set name - - + @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + @see lang::system::set_timezone } { - return [db_string charset_for_locale { - select mime_charset - from ad_locales - where locale = :locale - }] + lang::system::set_timezone $timezone } -ad_proc -public ad_locale_locale_from_lang { language } { - Returns the default locale for a language +ad_proc -deprecated -warn ad_locale_get_system_timezone { } { + Ask OpenACS what it thinks our timezone is. - @see ad_locale - @author Henry Minsky (hqm@mit.edu) - - @param language Name of a country, using ISO-3166 two letter code + @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) + @see lang::system::timezone +} { + return [lang::system::timezone] +} - @return IANA MIME character set name - - +ad_proc -deprecated -warn ad_locale_system_tz_offset { } { + @return number of hours to subtract from local (Oracle) time to get UTC + @see lang::system::timezone_utc_offset } { - return [db_string default_locale { - select locale - from ad_locales - where language = :language - and default_p = 't' - }] + return [lang::system::timezone_utc_offset] } +ad_proc -deprecated -public ad_locale_get_label { locale } { -ad_proc -public ad_locale_language_name { language } { + Returns the label (name) of locale - Returns the default locale for a language + @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) - @see ad_locale - @author Henry Minsky (hqm@mit.edu) - - @param language Name of a country, using ISO-3166 two letter code + @param locale Code for the locale, eg "en_US" - @return IANA MIME character set name - + @return String containing the label for the locale - } { - return [db_string default_locale { - select nls_language - from ad_locales - where language = :language + return [db_string select_locale_label { + select label + from ad_locales + where locale = :locale }] } - Index: openacs-4/packages/acs-lang/tcl/locale-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/locale-procs.xql,v diff -u -r1.1 -r1.2 --- openacs-4/packages/acs-lang/tcl/locale-procs.xql 2 May 2001 20:15:34 -0000 1.1 +++ openacs-4/packages/acs-lang/tcl/locale-procs.xql 7 Oct 2002 14:32:46 -0000 1.2 @@ -1,39 +1,35 @@ - + - - select mime_charset - from ad_locales - where locale = :locale - + select locale + from ad_locale_user_prefs + where user_id = :user_id - + - - + + - - select locale - from ad_locales - where language = :language - and default_p = 't' - + select count(*) + from ad_locale_user_prefs + where user_id = :user_id - + - - + + - - select locale - from ad_locales - where language = :language - and default_p = 't' - + update ad_locale_user_prefs set locale = :locale where user_id = :user_id - + - + + + + insert into ad_locale_user_prefs (user_id, locale) values (:user_id, :locale) + + + 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.3 -r1.4 --- openacs-4/packages/acs-lang/tcl/localization-procs.tcl 10 Sep 2002 22:22:09 -0000 1.3 +++ openacs-4/packages/acs-lang/tcl/localization-procs.tcl 7 Oct 2002 14:32:46 -0000 1.4 @@ -14,31 +14,17 @@ } -ad_proc -private ad_locale_repeat {str k} { - - Repeats a string. - - @param str String to repeat - @param k Number of times to repeat - @return Repeated string +ad_proc -private ad_locale_escape_vars_if_not_null { + list } { - set out {} - for {set i 0} {$i < $k} {incr i} { - append out $str - } - return $out -} - -ad_proc -private ad_locale_escape_vars_if_not_null {list} { - Processes a list of variables before they are passed into a regexp command. @param list List of variable names } { foreach lm $list { upvar $lm foreign_var - if {[exists_and_not_null foreign_var]} { + if { [exists_and_not_null foreign_var] } { set foreign_var "\[$foreign_var\]" } } @@ -52,7 +38,7 @@ Converts a number to its canonical representation by stripping everything but the decimal seperator and triming left 0's so it - wont be octal. It can process the following types of numbers: + won't be octal. It can process the following types of numbers: