Index: openacs-4/packages/acs-core-docs/www/i18n-introduction.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/i18n-introduction.html,v diff -u -r1.4 -r1.4.2.1 --- openacs-4/packages/acs-core-docs/www/i18n-introduction.html 4 Mar 2004 14:09:22 -0000 1.4 +++ openacs-4/packages/acs-core-docs/www/i18n-introduction.html 18 Apr 2004 11:55:50 -0000 1.4.2.1 @@ -1,4 +1,4 @@ -
+
This document describes how to develop internationalized OpenACS packages, including writing new packages with internationalization and converting old packages. Text that @@ -12,27 +12,17 @@ Otherwise, your package will not be usable for all locales.
The main difference between monolingual and internationalized - packages is that all user-visible text in an internationalized + packages is that all user-visible text in the code of an internationalized package are coded as "message keys." The message keys correspond to a message catalog, which contains versions of the - text for each available language. Both script files - (ADP/TCL) and APM parameters are affected. + text for each available language. Script files (.adp and .tcl and .vuh), database files (.sql), and APM parameters are affected. +
Other differences include: all dates read or written to the database must use internationalized functions. All displayed dates must use internationalized functions. All displayed numbers must use internationalized functions. -
- For multilingual websites we recommend using the UTF8 - charset. In order for AOLserver to use utf8 you need to set - the config parameters OutputCharset and - URLCharset to utf-8 in your AOLserver config file (use the etc/config.tcl - template file). This is the default for OpenACS 5.1 and later. For sites running on Oracle you need to make - sure that AOLserver is running with the NLS_LANG environment - variable set to .UTF8. You should set this variable in the - nsd-oracle run script (use the - acs-core-docs/www/files/nds-oracle.txt template file). -
+
OpenACS does not have a general system for supporting multiple, localized versions of user-input content. This document currently refers only to internationalizing the text in the package user interface.
Localizable text must be handled in ADP files, in TCL files, and in APM Parameters. OpenACS provides two approaches, message keys and localized ADP files. For ADP pages which are mostly @@ -42,7 +32,7 @@ which are static and mostly text, it may be easier to create a new ADP page for each language. In this case, the pages are distinguished by a file naming convention. -
If the request processor finds a file named filename.locale.adp, where locale matches the user's locale, it will process that file instead of filename.adp. For example, for a user with locale tl_PH, the file index.tl_PH.adp, if found, will be used instead of index.adp. The locale-specific file should thus contain text in the language appropriate for that locale. The code in the page, however, should still be in English. Message keys are still processed.
+
If the request processor finds a file named filename.locale.adp, where locale matches the user's locale, it will process that file instead of filename.adp. For example, for a user with locale tl_PH, the file index.tl_PH.adp, if found, will be used instead of index.adp. The locale-specific file should thus contain text in the language appropriate for that locale. The code in the page, however, should still be in English. Message keys are processed normally.
Internationalizing templates is about replacing human readable text in a certain language with internal message keys, which can then be dynamically replaced with real human language in @@ -97,17 +87,13 @@ \#package_key.message_key\#. In Tcl files all message lookups *must* be on either of the following formats:
-
Typical static key lookup: [_ package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation.
+ Static key lookup with non-default locale: [lang::message::lookup $locale package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation.
Dynamic key lookup: [lang::util::localize $var_with_embedded_message_keys] - In this case the message keys in the variable var_with_embedded_message_keys must appear as string literals \#package_key.message_key\# somewhere in the code. Here is an example of a dynamic lookup: - - - set message_key_array { - dynamic_key_1 \#package_key.message_key1\# - dynamic_key_2 \#package_key.message_key2\# - } +
set message_key_array { + dynamic_key_1 \#package_key.message_key1\# + dynamic_key_2 \#package_key.message_key2\# +} set my_text [lang::util::localize $message_key_array([get_dynamic_key])]@@ -116,16 +102,20 @@ context bars, and form labels and options. Many times the texts are enclosed in double quotes. The following is an example of grep commands that can be used on Linux to highlight translatable text in TCL files: -
- # Find text in double quotes - find -iname '*.tcl'|xargs egrep -i '"[a-z]' - # Find untranslated text in form labels, options and values - find -iname '*.tcl'|xargs egrep -i '\-(options|label|value)'|egrep -v '<#'|egrep -v '\-(value|label|options)[[:space:]]+\$[a-zA-Z_]+[[:space:]]*\\?[[:space:]]*$' - # Find text in page titles and context bars - find -iname '*.tcl'|xargs egrep -i 'set (title|page_title|context_bar) '|egrep -v '<#' - # Find text in error messages - find -iname '*.tcl'|xargs egrep -i '(ad_complain|ad_return_error)'|egrep -v '<#' -+
+# Find text in double quotes +find -iname '*.tcl'|xargs egrep -i '"[a-z]' + +# Find untranslated text in form labels, options and values +find -iname '*.tcl'|xargs egrep -i '\-(options|label|value)'|egrep -v '<#'|egrep -v '\-(value|label|options)[[:space:]]+\$[a-zA-Z_]+[[:space:]]*\\?[[:space:]]*$' + +# Find text in page titles and context bars +find -iname '*.tcl'|xargs egrep -i 'set (title|page_title|context_bar) '|egrep -v '<#' + +# Find text in error messages +find -iname '*.tcl'|xargs egrep -i '(ad_complain|ad_return_error)'|egrep -v '<#' + +
You may mark up translatable text in TCL library files and TCL pages with temporary tags on the <#key text#> syntax. If you have a sentence or paragraph of text with @@ -154,47 +144,43 @@
Alternatively, you may pass in an array list of the variable values to be interpolated into the message so that our example becomes: -
- set msg_subst_list [list subject [parameter::get -localize -parameter classes_pretty_name] - class_instances [parameter::get -localize -parameter class_instances_pretty_plural]] ++set msg_subst_list [list subject [parameter::get -localize -parameter classes_pretty_name] class_instances [parameter::get -localize -parameter class_instances_pretty_plural]] - ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted $msg_subst_list] -++ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted $msg_subst_list] +
When we were done going through the tcl files we ran the following commands to check for mistakes: -
- # Message tags should usually not be in curly braces since then the message lookup may not be - # executed then (you can usually replace curly braces with the list command). Find message tags - # in curly braces (should return nothing, or possibly a few lines for inspection) - find -iname '*.tcl'|xargs egrep -i '\{.*<#' - # Check if you've forgotten space between default key and text in message tags (should return nothing) - find -iname '*.tcl'|xargs egrep -i '<#_[^ ]' - # Review the list of tcl files with no message lookups - for tcl_file in $(find -iname '*.tcl'); do egrep -L '(<#|\[_)' $tcl_file; done -+
+# Message tags should usually not be in curly braces since then the message lookup may not be +# executed then (you can usually replace curly braces with the list command). Find message tags +# in curly braces (should return nothing, or possibly a few lines for inspection) +find -iname '*.tcl'|xargs egrep -i '\{.*<#' + +# Check if you've forgotten space between default key and text in message tags (should return nothing) +find -iname '*.tcl'|xargs egrep -i '<#_[^ ]' + +# Review the list of tcl files with no message lookups +for tcl_file in $(find -iname '*.tcl'); do egrep -L '(<#|\[_)' $tcl_file; done +
When you feel ready you may vist your package in the package manager and run the action "Replace tags with keys and insert into catalog" on the TCL files that you've edited to replace the temporary tags with calls to the message lookup procedure. -
- This section describes how to check that the set of keys used in - message lookups in tcl, adp, and info files and the set of keys in - the catalog file are identical. The scripts below assume that - message lookups in adp and info files are on the format - \#package_key.message_key\#, and that message lookups in tcl files - are always is done with one of the valid lookups described above. The script further assumes - that you have perl installed and in your path. Run the script like - this: -
- acs-lang/bin/check-catalog.sh package_key -- where package_key is the key of the package that you want to - test. If you don't provide the package_key argument then all - packages with catalog files will be checked. - The script will run its checks primarily on en_US xml catalog files. -
+
+ Most date, time, and number variables are calculated in TCL files. Dates and times must be converted when stored in the database, + when retrieved from the database, and when displayed. All dates + are stored in the database in the server's timezone, which is an + APM Parameter set at + /acs-lang/admin/set-system-timezone + and readable at + lang::system::timezone.. When + retrieved from the database and displayed, dates and times must + be localized to the user's locale. +
Some parameters contain text that need to be localized. In this case, instead of storing the real text in the parameter, you should use message keys using the short notation above, @@ -220,41 +206,4 @@
Developers are responsible for creating the keys in the message catalog, which is available at /acs-lang/admin/ -
- Dates and times must be converted when stored in the database, - when retrieved from the database, and when displayed. All dates - are stored in the database in the server's timezone, which is an - APM Parameter set at - /acs-lang/admin/set-system-timezone - and readable at - lang::system::timezone.. When - retrieved from the database and displayed, dates and times must - be localized to the user's locale. -
- Get the date in ANSI format from the database (YYYY-MM-DD - HH24:MI:SS; the time portion is optional). By convention, - we identify dates in ansi format by ending the column name - with _ansi. - Example:
select to_char(posting_date, 'YYYY-MM-DD HH24:MI:SS') as posting_date_ansi - from table -
- Use the Tcl command lc_time_fmt to format the - date in "pretty" format. Several standard formats localize automatically: -
- %c: Long date and time (Mon November 18, 2002 12:00 AM) -
- %x: Short date (11/18/02) -
- %X: Time (12:00 AM) -
- %q: Long date without weekday (November 18, 2002) -
- %Q: Long date with weekday (Monday November 18, 2002) -
- The "q" format strings are OpenACS additions; the rest follow unix standards (see man - strftime). -
set posting_date_pretty [lc_time_fmt $posting_date_ansi "%q"]
- Use the *_pretty version in your ADP page. -
- To internationalize numbers, use lc_numeric $value, which formats the number using the appropriate decimal point and thousand separator for the locale. -