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.13 -r1.14
--- openacs-4/packages/acs-lang/acs-lang.info	25 Oct 2002 15:19:10 -0000	1.13
+++ openacs-4/packages/acs-lang/acs-lang.info	28 Oct 2002 12:32:42 -0000	1.14
@@ -2,8 +2,8 @@
 <!-- Generated by the OpenACS Package Manager -->
 
 <package key="acs-lang" url="http://www.openacs.org/acs-repository/apm/packages/acs-lang" type="apm_service">
-    <package-name>Localization</package-name>
-    <pretty-plural>Localization</pretty-plural>
+    <package-name>OpenACS Localization Utils</package-name>
+    <pretty-plural>OpenACS Localization Utils</pretty-plural>
     <initial-install-p>t</initial-install-p>
     <singleton-p>t</singleton-p>
 
@@ -12,10 +12,10 @@
         <database>oracle</database>
         <database>postgresql</database>
     </database-support>
-        <owner url="mailto:peter@collaboraid.biz">Peter Marklund</owner>
+        <owner url="mailto:hqm@ai.mit.edu">Henry Minsky</owner>
         <summary>OpenACS Internationalization Utilities</summary>
         <release-date>2002-09-26</release-date>
-        <vendor url="http://www.collaboraid.biz/">Collaboraid</vendor>
+        <vendor url="http://www.arsdigita.com/">ArsDigita Corporation</vendor>
         <description format="text/html">OpenACS Internationalization Utilities. Routines for manipulating Locales,
 request processor hooks, templating, message catalog, and
 locale-specific formatting functions.
@@ -35,6 +35,8 @@
             <file path="ACS4.1b-PATCHES/tag-init.patch"/>
             <file path="ACS4.1b-PATCHES/util-procs.patch"/>
             <file type="package_spec" path="acs-lang.info"/>
+            <file type="shell" path="bin/check-catalog.sh"/>
+            <file type="shell" path="bin/mygrep"/>
             <file path="catalog/test.iso-8859-1.cat"/>
             <file type="data_model_create" db_type="oracle" path="sql/oracle/acs-lang-create.sql"/>
             <file type="data_model" db_type="oracle" path="sql/oracle/ad-locales-drop.sql"/>
@@ -51,6 +53,7 @@
             <file type="data_model_upgrade" db_type="postgresql" path="sql/postgresql/upgrade/upgrade-4.1-4.7d2.sql"/>
             <file type="data_model_upgrade" db_type="postgresql" path="sql/postgresql/upgrade/upgrade-4.7d2-4.7d3.sql"/>
             <file type="tcl_init" path="tcl/acs-lang-init.tcl"/>
+            <file type="tcl_procs" path="tcl/acs-lang-test-procs.tcl"/>
             <file type="tcl_procs" path="tcl/lang-catalog-procs.tcl"/>
             <file type="query_file" path="tcl/lang-catalog-procs.xql"/>
             <file type="query_file" db_type="oracle" path="tcl/lang-message-procs-oracle.xql"/>
@@ -102,6 +105,7 @@
             <file type="content_page" path="www/admin/localized-messages.tcl"/>
             <file type="content_page" path="www/admin/master.adp"/>
             <file type="content_page" path="www/admin/master.tcl"/>
+            <file type="content_page" path="www/admin/reload-cache.tcl"/>
             <file type="content_page" path="www/admin/test/catalog-test.adp"/>
             <file type="content_page" path="www/admin/test/catalog-test.tcl"/>
             <file type="content_page" path="www/admin/test/compile.tcl"/>
@@ -122,6 +126,7 @@
             <file type="content_page" path="www/admin/test/timezone.adp"/>
             <file type="content_page" path="www/admin/test/timezone.tcl"/>
             <file type="content_page" path="www/admin/test/tz-test.tcl"/>
+            <file type="content_page" path="www/admin/translator-mode-toggle.tcl"/>
             <file type="content_page" path="www/change-locale-include.adp"/>
             <file type="content_page" path="www/change-locale-include.tcl"/>
             <file type="content_page" path="www/change-locale.tcl"/>
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 -r1.5 -r1.6
--- openacs-4/packages/acs-lang/tcl/lang-message-procs.tcl	23 Oct 2002 11:49:18 -0000	1.5
+++ openacs-4/packages/acs-lang/tcl/lang-message-procs.tcl	28 Oct 2002 12:32:45 -0000	1.6
@@ -229,7 +229,20 @@
             set return_value $default
 
             if { [string equal $default "TRANSLATION MISSING"] } {
-                append return_value " - " $key                    
+                if { [lang::util::translator_mode_p] } {
+                    set key_split [split $key "."]
+                    set package_key_part [lindex $key_split 0]
+                    set message_key_part [lindex $key_split 1]
+
+                    set return_url [ad_conn url]
+                    if { [ns_getform] != "" } {
+                        append return_url "?[export_entire_form_as_url_vars]"
+                    }
+
+                    set return_value "<a href=\"/acs-lang/admin/edit-localized-message?[export_vars { { message_key $message_key_part } { locales $locale } { package_key $package_key_part } return_url }]\"><span style=\"background-color: yellow\">TRANSLATE NOW</span></a>"
+                } else {
+                    append return_value " - " $key
+                }
             }
         }
 
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 -r1.6 -r1.7
--- openacs-4/packages/acs-lang/tcl/lang-util-procs.tcl	23 Oct 2002 11:48:17 -0000	1.6
+++ openacs-4/packages/acs-lang/tcl/lang-util-procs.tcl	28 Oct 2002 12:32:45 -0000	1.7
@@ -61,7 +61,6 @@
     
         @author Peter marklund (peter@collaboraid.biz)
     } {
-
         set regexp_pattern {(?:^|[^\\])(\#[-a-zA-Z0-9_:\.]+\#)}
         return [get_regexp_indices $multilingual_string $regexp_pattern]
     }
@@ -319,7 +318,12 @@
             # Attempt a message lookup
             set message_value [_ [ad_locale request locale] $message_key]
             
-            regsub $replacement_string $subst_string $message_value subst_string
+            # Replace the string
+            # LARS: We don't use regsub here, because regsub interprets certain characters
+            # in the replacement string specially.
+            set subst_string [string range $string_with_hashes 0 [expr [lindex $item_idx 0]-1]]
+            append subst_string $message_value
+            append subst_string [string range $string_with_hashes [expr [lindex $item_idx 1]+1] end]
         }        
         
         return $subst_string
@@ -390,8 +394,24 @@
             set key "lt_[string range $key 0 20]"
         }
         return $key
-    }        
+    }
 
+    ad_proc -private convert_adp_variables_to_percentage_signs { text } {
+        Convert ADP variables to percentage_signs - that is the variable
+        notation used in acs-lang messages.
+
+        @author Peter Marklund
+    } {
+        # substitute array variable references
+        # loop to handle the case of adjacent variable references, like @a@@b@
+        while {[regsub -all [template::adp_array_variable_regexp] $text {\1%\2.\3%} text]} {}
+
+        # substitute simple variable references
+        while {[regsub -all [template::adp_variable_regexp] $text {\1%\2%} text]} {}
+
+        return $text
+    }
+
     ad_proc -public replace_adp_text_with_message_tags { 
         file_name
         mode
@@ -410,11 +430,19 @@
         - write : write changes in the file - it expects a list of keys and will insert them
           in the order implied by the report - a report is also returned.
 
-        The report is list of two lists: The first being a list of pairs (key, text with context)
-        and the second is a list of suspious looking garbage. In report mode the keys are suggested
-        keys and in write mode the keys are the keys supplied in the keys parameter.
+        @param file_name The name of the adp file to do replacements in.
+        @param mode      Either report or write.
+        @param keys      A list of keys to use for the texts that may be provided in write mode. If
+                         the keys are not provided then autogenerated keys will be used.
+                         If a supplied key is the empty string this indicates that the corresponding
+                         text should be left untouched.
 
+        @return The report is list of two lists: The first being a list of pairs (key, text with context)
+                and the second is a list of suspious looking garbage. In report mode the keys are suggested
+                keys and in write mode the keys are the keys supplied in the keys parameter.
+
         @author Christian Hvid
+        @author Peter Marklund
         @author Jeff Davis
 
     } {
@@ -441,21 +469,24 @@
                 if {![regexp {(^[^<]*?)(<.*)$} $s match text s x]} { 
                     set text $s
                     set s {}
-                } 
+                }  
+
+                regsub -all {@[a-zA-Z0-9_\.]+@} $text "" text_wo_variables
     
                 # make sure the string is non empty and contains at least one letter.
                 if {![empty_string_p $text] 
-                    && ![string is space $text] 
+                    && ![string is space $text_wo_variables] 
                     && [string match -nocase {*[A-Z]*} $text]
-                    && ![regexp {^\s*@[A-Za-z_.-]*@\s*$} $text]
-                    && ![string match {*&nbsp;*} $text]
-                    && ![string match {*@*} $text]
                     && ![string match {*\#*} $text]
                     && ![string match {*\{*} $text]
                     && ![string match {*\}*} $text]
                     && [string length $text] > 1
                 } {
                     regexp {^(\s*)(.*?)(\s*)$} $text match lead text lag
+
+                    set text_w_percentages [convert_adp_variables_to_percentage_signs $text]
+
+                    ns_log Notice "PM: text $text text_w_percentages $text_w_percentages"
     
                     if { $mode == "report" } {
                         # create a key for the text
@@ -464,13 +495,31 @@
 
                         lappend report [list $key "<code>[string range [remove_gt_lt $out$lead] end-20 end]<b><span style=background:#ffffc0>$text</span></b>[string range [remove_gt_lt $lag$s] 0 20]</code>" ]
                     } else {    
-                        if { [lindex $keys $n] != "" } {
-                            lappend report [list [lindex $keys $n] "<code>[string range [remove_gt_lt $out$lead] end-20 end]<b><span style=background:#ffffc0>$text</span></b>[string range [remove_gt_lt $lag$s] 0 20]</code>" ]
-                            append out "$lead<\#[lindex $keys $n] $text\#>$lag"
+                        # Write mode
+                        if { [llength $keys] != 0} {
+                            # Use keys supplied                            
+                            if { [lindex $keys $n] != "" } {
+                                # Use supplied key
+                                set write_key [lindex $keys $n]
+                            } else {
+                                # The supplied key for this index is empty so leave the text untouched
+                                set write_key ""
+                            }
                         } else {
+                            # No keys supplied - autogenerate a key
+                            set write_key [suggest_key $text]                            
+                        }
+
+                        if { ![empty_string_p $write_key] } {
+                            # Write tag to file
+                            lappend report [list ${write_key} "<code>[string range [remove_gt_lt $out$lead] end-20 end]<b><span style=background:#ffffc0>$text</span></b>[string range [remove_gt_lt $lag$s] 0 20]</code>" ]
+
+                            append out "$lead<\#${write_key} $text_w_percentages\#>$lag"
+                        } else {
+                            # Leave the text untouched
                             lappend garbage "<code>[string range [remove_gt_lt $out$lead] end-20 end]<b><span style=background:#ffffc0>$text </span></b>[string range [remove_gt_lt $lag$s] 0 20]</code>"
                             append out "$lead$text$lag"
-                        }
+                        }                        
                     }
 
                     incr n
@@ -522,6 +571,39 @@
         return [list $report $garbage]
     }
 
+    ad_proc -public translator_mode_p {} {
+        Whether translator mode is enabled for this session or
+        not. Translator mode will cause all non-translated messages to appear as a 
+        link to a page where the message can be translated, instead of the default
+        "not translated" message.
+        
+        @author Lars Pind (lars@collaboraid.biz)
+        @create-date October 24, 2002
+
+        @return 1 if translator mode is enabled, 0 otherwise.
+
+        @see lang::util::translator_mode_set
+    } {
+        return [ad_get_client_property -default 0 acs-lang translator_mode_p]
+    }
+    
+    ad_proc -public translator_mode_set {
+        translator_mode_p
+    } {
+        Sets whether translator mode is enabled for this session or
+        not. 
+        
+        @author Lars Pind (lars@collaboraid.biz)
+        @create-date October 24, 2002
+
+        @param translator_mode_p 1 if you want translator mode to be enabled, 0 otherwise.
+
+        @see lang::util::translator_mode_p
+    } {
+        ad_set_client_property acs-lang translator_mode_p $translator_mode_p
+    }
+    
+
 }
 
 #####
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.4 -r1.5
--- openacs-4/packages/acs-lang/tcl/locale-procs.tcl	8 Oct 2002 08:48:48 -0000	1.4
+++ openacs-4/packages/acs-lang/tcl/locale-procs.tcl	28 Oct 2002 12:32:45 -0000	1.5
@@ -124,7 +124,8 @@
     } {
         set user_id [ad_conn user_id]
         if { $user_id == 0 } {
-            return ""
+            # Not logged in, use a session-based client property
+            return [ad_get_client_property -cache t "acs-lang" "user_locale"]
         }
     
         # Pssst! We don't actually use this package thing, 
@@ -160,6 +161,8 @@
     } {
         set user_id [ad_conn user_id]
         if { $user_id == 0 } {
+            # Not logged in, use a session-based client property
+            ad_set_client_property -persistent t "acs-lang" "user_locale" $locale
             return
         }
     
@@ -173,9 +176,15 @@
 
         set user_locale_exists_p [db_string user_locale_exists_p {}]
         if { $user_locale_exists_p } {
-            db_dml update_user_locale {}
+            if { ![empty_string_p $locale] } {
+                db_dml update_user_locale {}
+            } else {
+                db_dml delete_user_locale {}
+            }
         } else {
-            db_dml insert_user_locale {}
+            if { ![empty_string_p $locale] } {
+                db_dml insert_user_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.2 -r1.3
--- openacs-4/packages/acs-lang/tcl/locale-procs.xql	7 Oct 2002 14:32:46 -0000	1.2
+++ openacs-4/packages/acs-lang/tcl/locale-procs.xql	28 Oct 2002 12:32:45 -0000	1.3
@@ -32,4 +32,11 @@
       </querytext>
    </fullquery>
 
+
+   <fullquery name="lang::user::set_locale.delete_user_locale">
+      <querytext>
+        delete from ad_locale_user_prefs where user_id = :user_id
+      </querytext>
+   </fullquery>
+
 </queryset>
Index: openacs-4/packages/acs-lang/tcl/test/acs-lang-test.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/tcl/test/Attic/acs-lang-test.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-lang/tcl/test/acs-lang-test.tcl	21 Oct 2002 11:39:13 -0000	1.1
+++ openacs-4/packages/acs-lang/tcl/test/acs-lang-test.tcl	28 Oct 2002 12:32:47 -0000	1.2
@@ -5,6 +5,18 @@
     @creation-date 18 October 2002
 }
 
+namespace eval lang::test {
+
+    ad_proc get_dir {} {
+        The test directory of the acs-lang package (where this file resides).
+
+        @author Peter Marklund (peter@collaboraid.biz)
+        @creation-date 28 October 2002
+    } {
+        return "[acs_package_root_dir acs-lang]/tcl/test"
+    }
+}
+
 aa_register_case util__replace_temporary_tags_with_lookups {
     Primarily tests lang::util::replace_temporary_tags_with_lookups,
     Also tests the procs lang::catalog::export_messages_to_file, lang::catalog::parse,
@@ -18,7 +30,7 @@
     @creation-date 18 October 2002
 } {
     # The files involved in the test
-    set test_dir "[acs_package_root_dir acs-lang]/tcl/test"    
+    set test_dir [lang::test::get_dir]
     set catalog_file "${test_dir}/acs-lang.en_US.ISO-8859-1.xml"
     set backup_file_suffix ".orig"
     set catalog_backup_file "${catalog_file}${backup_file_suffix}"
@@ -113,6 +125,68 @@
   }
 }
 
+aa_register_case util__convert_adp_variables_to_percentage_signs {
+    Tests the lang::util::convert_adp_variables_to_percentage_signs proc.
+
+    @author Peter Marklund (peter@collaboraid.biz)
+    @creation-date 25 October 2002
+} {
+    set adp_chunk "<property name=\"title\">@array.variable_name@ @variable_name2@ peter@collaboraid.biz</property>"
+
+    set adp_chunk_converted [lang::util::convert_adp_variables_to_percentage_signs $adp_chunk]
+    set adp_chunk_expected "<property name=\"title\">%array.variable_name% %variable_name2% peter@collaboraid.biz</property>"
+
+    aa_true "adp vars should be subsituted with percentage sings" [string equal $adp_chunk_converted \
+                                                                                $adp_chunk_expected]
+
+    # Test that a string can start with adp vars
+    set adp_chunk "@first_names@ @last_name@&nbsp;peter@collaboraid.biz"
+    set adp_chunk_converted [lang::util::convert_adp_variables_to_percentage_signs $adp_chunk]
+    set adp_chunk_expected "%first_names% %last_name%&nbsp;peter@collaboraid.biz"
+    aa_true "adp vars should be subsituted with percentage sings" [string equal $adp_chunk_converted \
+                                                                                $adp_chunk_expected]
+}
+
+aa_register_case util__replace_adp_text_with_message_tags {
+    Test the lang::util::replace_adp_text_with_message_tags proc.
+
+    @author Peter Marklund (peter@collaboraid.biz)
+    @creation-date 28 October 2002
+} {
+    # File paths used
+    set adp_file_path "[lang::test::get_dir]/adp_tmp_file.adp"
+
+    # Write the adp test file
+    set adp_file_id [open $adp_file_path w]
+    puts $adp_file_id "<master src=\"master\">
+<property name=\"title\">@first_names@ @last_name@&nbsp;peter@collaboraid.biz</property>
+<property name=\"context_bar\">@context_bar@</property>
+Test text"
+    close $adp_file_id
+
+    # Do the substitutions
+    lang::util::replace_adp_text_with_message_tags $adp_file_path "write"
+
+    # Read the changed test file
+    set adp_file_id [open $adp_file_path r]
+    set adp_contents [read $adp_file_id]
+    close $adp_file_id
+
+    set expected_adp_pattern {<master src=\"master\">
+<property name=\"title\"><#[a-zA-Z_]+ %first_names% %last_name%&nbsp;peter@collaboraid.biz#></property>
+<property name=\"context_bar\">@context_bar@</property>
+<#[a-zA-Z_]+ Test text\s*}
+
+    ns_log Notice "adp_contents $adp_contents"
+
+    # Assert proper replacements have been done
+    aa_true "replacing adp text with tags" \
+            [regexp $expected_adp_pattern $adp_contents match]
+
+    # Remove the adp test file
+    file delete $adp_file_path
+}
+
 aa_register_case message__format {
     Tests the lang::message::format proc
 
@@ -129,4 +203,3 @@
     aa_true "the frog should jump across the fence" [string equal $subst_message \
                                                                   $expected_message]
 }
-
Index: openacs-4/packages/acs-lang/www/change-locale-include.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/www/change-locale-include.adp,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-lang/www/change-locale-include.adp	7 Oct 2002 14:32:47 -0000	1.1
+++ openacs-4/packages/acs-lang/www/change-locale-include.adp	28 Oct 2002 12:32:49 -0000	1.2
@@ -1,20 +1 @@
-Locale for this request: <%= [ad_conn locale] %><br />
-
-<table width="100%">
-<tr>
-<td>
-<formtemplate id="locale_form"></formtemplate>
-</td>
-
-<!-- Cannot use this stuff as not all message keys have been looked up at this point
-<if @message_debug_html@ not nil>
-<td>
-Using message Keys:
-<p>
-@message_debug_html@
-</p>
-</td>
-</if>
--->
-</tr>
-</table>
\ No newline at end of file
+<formtemplate id="locale"></formtemplate>
Index: openacs-4/packages/acs-lang/www/change-locale-include.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/www/change-locale-include.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-lang/www/change-locale-include.tcl	7 Oct 2002 14:32:47 -0000	1.1
+++ openacs-4/packages/acs-lang/www/change-locale-include.tcl	28 Oct 2002 12:32:49 -0000	1.2
@@ -3,54 +3,31 @@
 # a user
 # @author Peter Marklund (peter@collaboraid.biz)
 
-set user_id [ad_conn user_id]
-
-form create locale_form -action "/acs-lang/change-locale"
-
-set locale_option_list [list]
-db_foreach locale_loop { select locale, label from ad_locales } {
-    lappend locale_option_list [list $label $locale]
+if { ![exists_and_not_null return_url] } {
+    # Use referer header
+    set return_url [ns_set iget [ns_conn headers] referer]
 }
 
-set user_locale [lang::user::locale]
+form create locale
 
-set site_wide_locale [lang::system::locale]
-
-element create locale_form return_url \
+element create locale return_url \
         -datatype text \
         -widget hidden \
-        -value "[ad_conn url]?[ad_conn query]"
+        -optional \
+        -value $return_url
 
-element create locale_form site_wide_locale \
+element create locale user_locale \
         -datatype text \
         -widget select \
-        -label "Site Wide Locale" \
-        -options $locale_option_list \
-        -value $site_wide_locale
+        -label "Your Preferred Locale" \
+        -options [db_list_of_lists locale_loop { select label, locale from ad_locales }] \
+        -value [lang::user::locale]
 
-if { $user_id != "0" } {
-    element create locale_form user_locale \
-        -datatype text \
-        -widget select \
-        -label "User Locale Preference" \
-        -options $locale_option_list \
-        -value $user_locale
-} else {
-    element create locale_form user_preference_inform \
-            -datatype text \
-            -widget inform \
-            -label  "User Locale Preference" \
-            -value "Please log in to specify a user preference"
-}
+if { [form is_valid locale] } {
+    form get_values locale user_locale return_url
 
-#global message_debug_map
+    lang::user::set_locale $user_locale
 
-set message_debug_html ""
-#if { [info exists message_debug_map] } {
-
-#    set message_debug_html "<ul>"
-#    foreach item $message_debug_map {
-#        append message_debug_html "<li>[lindex $item 0] - [lindex $item 1]</li>"
-#    }
-#    append message_debug_html "</ul>"
-#}
+    ad_returnredirect $return_url
+    ad_script_abort
+}
\ No newline at end of file
Index: openacs-4/packages/acs-lang/www/change-locale.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-lang/www/change-locale.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/acs-lang/www/change-locale.tcl	7 Oct 2002 14:32:47 -0000	1.1
+++ openacs-4/packages/acs-lang/www/change-locale.tcl	28 Oct 2002 12:32:49 -0000	1.2
@@ -1,12 +1,10 @@
 ad_page_contract {
 
 } {
-    {user_locale ""}
-    site_wide_locale
+    user_locale
     return_url
 }
 
 lang::user::set_locale $user_locale
-lang::system::set_locale $site_wide_locale
 
 ad_returnredirect $return_url