Integrate Locale::Maketext for string translations
authorBill Erickson <berick@esilibrary.com>
Thu, 3 Feb 2011 21:47:59 +0000 (16:47 -0500)
committerBill Erickson <berick@esilibrary.com>
Thu, 3 Feb 2011 21:47:59 +0000 (16:47 -0500)
Added support for configuring supported locales and specifying message
catalogs as gettext .po or .mo files.  All locales default to native
template strings when no translation is provided.

Updated oils_web config and added some inline template examples

Open-ILS/examples/oils_web.xml.example
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGWeb.pm
Open-ILS/web/templates/default/opac/home.tt2
Open-ILS/web/templates/default/opac/results.tt2

index e5f0efb..0728082 100644 (file)
     <!-- Turn on template-toolkit debugging, which reports on undefined blocks, macros, etc. -->
     <debug_template>false</debug_template>
 
+    <!-- 
+        Supported locales.  Locales with no message catalog will use the native template strings.
+        All locales will fall back to native strings when a given string is not in the catalog
+    -->
+    <locales>
+        <en_US/>
+        <en_CA>/openils/var/data/locale/messages.en_CA.po</en_CA>
+        <fr_CA>/openils/var/data/locale/messages.fr_CA.po</fr_CA>
+    </locales>
+
     <!-- Where templates can be found.  Paths will be checked in the order entered here.
          It's possible to override individual or sets of templates by putting them into
          a path in front of the default template path -->
index e804562..8f19a07 100644 (file)
@@ -16,6 +16,7 @@ use constant OILS_HTTP_COOKIE_LOCALE => 'oils:locale';
 my $web_config;
 my $web_config_file;
 my $web_config_edit_time;
+my %lh_cache; # locale handlers
 
 sub import {
     my $self = shift;
@@ -52,7 +53,7 @@ sub handler {
         DEBUG => $ctx->{debug_template}
     });
 
-    unless($tt->process($template, {ctx => $ctx})) {
+    unless($tt->process($template, {ctx => $ctx, l => set_text_handler($ctx, $r)})) {
         $r->log->warn('Template error: ' . $tt->error);
         return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -60,6 +61,24 @@ sub handler {
     return Apache2::Const::OK;
 }
 
+sub set_text_handler {
+    my $ctx = shift;
+    my $r = shift;
+
+    my $locale = $ctx->{locale};
+    $locale =~ s/-/_/g;
+
+    $r->log->info("messages locale = $locale");
+
+    unless($lh_cache{$locale}) {
+        $r->log->info("Unsupported locale: $locale");
+        $lh_cache{$locale} = $lh_cache{'en_US'};
+    }
+
+    return sub { return $lh_cache{$locale}->maketext(@_); };
+}
+
+
 
 sub run_context_loader {
     my $r = shift;
@@ -117,11 +136,10 @@ sub load_context {
     $ctx->{base_url} = $cgi->url(-base => 1);
     $ctx->{skin} = $cgi->cookie(OILS_HTTP_COOKIE_SKIN) || 'default';
     $ctx->{theme} = $cgi->cookie(OILS_HTTP_COOKIE_THEME) || 'default';
+
     $ctx->{locale} = 
         $cgi->cookie(OILS_HTTP_COOKIE_LOCALE) || 
         parse_accept_lang($r->headers_in->get('Accept-Language')) || 'en-US';
-    $r->log->debug('skin = ' . $ctx->{skin} . ' : theme = ' . 
-        $ctx->{theme} . ' : locale = ' . $ctx->{locale});
 
     my $mprefix = $ctx->{media_prefix};
     if($mprefix and $mprefix !~ /^http/ and $mprefix !~ /^\//) {
@@ -129,7 +147,6 @@ sub load_context {
         $ctx->{media_prefix} = ($cgi->https) ? "https://$mprefix" : "http://$mprefix";
     }
 
-
     return $ctx;
 }
 
@@ -223,6 +240,38 @@ sub check_web_config {
     }
 }
 
+# Create an I18N sub-module for each supported locale
+# Each module creates its own MakeText lexicon by parsing .po/.mo files
+sub load_locale_handlers {
+    my $ctx = shift;
+    my $locales = $ctx->{locales};
+
+    for my $lang (keys %$locales) {
+        my $messages = $locales->{$lang};
+        $messages = '' if ref $messages; # empty {}
+
+        # TODO Can we do this without eval?
+        my $eval = <<EVAL;
+            package OpenILS::WWW::EGWeb::I18N::$lang;
+            use base 'OpenILS::WWW::EGWeb::I18N';
+            if(\$messages) {
+                use Locale::Maketext::Lexicon::Gettext;
+                if(open F, '$messages') {
+                    our %Lexicon = (%Lexicon, %{ Locale::Maketext::Lexicon::Gettext->parse(<F>) });
+                    close F;
+                } else {
+                    warn "unable to open messages file: $messages"; 
+                }
+            }
+EVAL
+        eval $eval;
+        warn "$@\n" if $@; # TODO better logging
+        $lh_cache{$lang} = "OpenILS::WWW::EGWeb::I18N::$lang"->new;
+    }
+}
+
+
+
 sub parse_config {
     my $cfg_file = shift;
     my $data = XML::Simple->new->XMLin($cfg_file);
@@ -236,6 +285,8 @@ sub parse_config {
     $ctx->{debug_template} = ( ($data->{debug_template}||'')  =~ /true/io) ? 1 : 0;
     $ctx->{default_template_extension} = $data->{default_template_extension} || 'tt2';
     $ctx->{web_dir} = $data->{web_dir};
+    $ctx->{locales} = $data->{locales};
+    load_locale_handlers($ctx);
 
     my $tpaths = $data->{template_paths}->{path};
     $tpaths = [$tpaths] unless ref $tpaths;
@@ -268,5 +319,9 @@ sub new {
     return bless(\%args, $class);
 }
 
+# base class for all supported locales
+package OpenILS::WWW::EGWeb::I18N;
+use base 'Locale::Maketext';
+our %Lexicon = (_AUTO => 1);
 
 1;
index 9faf5e6..03b2ad1 100644 (file)
@@ -15,7 +15,7 @@
     <form action='./results' method='GET'>
         <input type='text' name='query' size='50' value='[% query %]'/>
         [% PROCESS build_org_selector name='loc' %]
-        <input type='submit'/>
+        <input type='submit' value='[% l('Go!') %]'/>
         <input type='hidden' name='page' value='0'/>
     </form>
 </div>
index 27f960d..9ecead4 100644 (file)
@@ -72,7 +72,7 @@
         </td>
         <td id='right_block'>
             <div>
-                <span>Hits: [% ctx.hit_count %] / Page [% page + 1 %] of [% page_count %]</span>
+                <span>[% l('Hits: [_1] / Page [_2] of [_3]', ctx.hit_count, page + 1, page_count) %]</span>
                 [% 
                     q = query | url;
                     np_link = '?query=' _ q;