File:  [LON-CAPA] / loncom / localize / lonlocal.pm
Revision 1.19: download - view: text, annotated - select for diffs
Sat Oct 4 20:49:40 2003 UTC (20 years, 6 months ago) by www
Branches: MAIN
CVS tags: HEAD
Internationalization, and in particular, lonlocal:locallocaltime and
Japanese dates.

# The LearningOnline Network with CAPA
# Localization routines
#
# $Id: lonlocal.pm,v 1.19 2003/10/04 20:49:40 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
######################################################################
######################################################################

=pod

=head1 NAME

Apache::lonlocal - provides localization services

=head1 SYNOPSIS

lonlocal provides localization services for LON-CAPA programmers based
on Locale::Maketext. See
C<http://search.cpan.org/dist/Locale-Maketext/lib/Locale/Maketext.pod>
for more information on Maketext.

=head1 OVERVIEWX<internationalization>

As of LON-CAPA 1.1, we've started to localize LON-CAPA using the
Locale::Maketext module. Internationalization is the bulk of the work
right now (pre-1.1); localizing can be done anytime, and involves 
little or no programming.

The internationalization process involves putting a wrapper around
on-screen user messages and menus and turning them into keys,
which the MaketextX<Maketext> library translates into the desired
language output using a look-up table ("lexicon").X<lexicon>

As keys we are currently using the plain English messages, and
Maketext is configured to replace the message by its own key if no
translation is found. This makes it easy to phase in the
internationalization without disturbing the screen output.

Internationalization is somewhat tedious and effectively impossible
for a non-fluent speaker to perform, but is fairly easy to create
translations, requiring no programming skill. As a result, this is one
area where you can really help LON-CAPA out, even if you aren't a
programmer, and we'd really appreciate it.

=head1 How To Localize Handlers For Programmers

Into the "use" section of a module, we need to insert

 use Apache::lonlocal;

Note that there are B<no parentheses>, we B<want> to pollute our
namespace. 

Inside might be something like this

 sub message {
     my $status=shift;
     my $message='Status unknown';
     if ($status eq 'WON') {
        $message='You have won.';
     } elsif ($status eq 'LOST') {
        $message='You are a total looser.';
     }
     return $message;
 }
 ...
 $r->print('<h3>Gamble your Homework Points</h3>');
 ...
 $r->print(<<ENDMSG);
 <font size="1">Rules:</font>
 <font size="0">No purchase necessary. Illegal where not allowed.</font>
 ENDMSG

We have to now wrap the subroutine &mt()X<mt> ("maketext") around our 
messages, but not around markup, etc. We also want minimal disturbance. 
The first two examples are easy:

 sub message {
     my $status=shift;
     my $message='Status unknown';
     if ($status eq 'WON') {
        $message='You have won.';
     } elsif ($status eq 'LOST') {
        $message='You are a total looser.';
     }
     return &mt($message);
 }
 ...
 $r->print('<h3>'.&mt('Gamble your Homework Points').'</h3>');

The last one is a bummer, since you cannot call subroutines inside of 
(<<MARKER). I have written a little subroutine to generate a translated 
hash for that purpose:

 my %lt=&Apache::lonlocal::texthash('header' => 'Rules', 'disclaimer' => 
 'No purchase necessary. Illegal where not allowed.');
 $r->print(<<ENDMSG);
 <font size="1">$lt{'header'}:</font>
 <font size="0">$lt{'disclaimer'}</font>
 ENDMSG

As a programmer, your job is done here. If everything worked, you 
should see no changes on the screen.

=head1 How To Localize LON-CAPA for Translators

As a translator, you need to provide the lexicon for the keys, which in 
this case is the plain text message. The lexicons sit in 
loncom/localize/localize, with the language code as filename, for 
example de.pm for the German translation. The file then simply looks 
like this:

    'You have won.'
 => 'Sie haben gewonnen.',

    'You are a total looser.'
 => 'Sie sind der totale Verlierer.',

    'Rules'
 => 'Regeln',

    'No purchase necessary. Illegal where not allowed.'
 => 'Es ist erlaubt, einfach zu verlieren, und das ist Ihre Schuld.'


Comments may be added with the # symbol, which outside of a string
(the things with the apostrophe surrounding them, which are the 
keys and translations) will cause the translation routines to
ignore the rest of the line.

This is a relatively easy task, and any help is appreciated.

Maketext can do a whole lot more, see
C<http://search.cpan.org/dist/Locale-Maketext/lib/Locale/Maketext.pod>
but for most purposes, we do not have to mess with that.

=cut

package Apache::lonlocal;

use strict;
use Apache::localize;
use Apache::File;
use locale;
use POSIX qw(locale_h);

require Exporter;

our @ISA = qw (Exporter);
our @EXPORT = qw(mt);

my $reroute;

# ========================================================= The language handle

use vars qw($lh);

# ===================================================== The "MakeText" function

sub mt (@) {
    unless ($ENV{'environment.translator'}) {
	if ($lh) {
	    return $lh->maketext(@_);
	} else {
	    return @_;
	}
    } else {
	if ($lh) {
	    my $trans=$lh->maketext(@_);
	    my $link='<a target="trans" href="/cgi-bin/translator.pl?arg1='.
		&Apache::lonnet::escape($_[0]).'&arg2='.
		&Apache::lonnet::escape($_[1]).'&arg3='.
		&Apache::lonnet::escape($_[2]).'&lang='.
		$ENV{'environment.translator'}.
		'">[['.$trans.']]</a>';
	    if ($ENV{'transreroute'}) {
		$reroute.=$link;
		return $trans;
	    } else {
		return $link;
	    }
	} else {
	    return @_;
	}
    }
}

# ============================================================== What language?

sub current_language {
    my $lang=$lh->maketext('language_code');
    return ($lang eq 'language_code'?'en':$lang);
}

# ============================================================== What encoding?

sub current_encoding {
    if ($lh) {
	my $enc=$lh->maketext('char_encoding');
	return ($enc eq 'char_encoding'?'':$enc);
    } else {
	return undef;
    }
}

# =============================================================== Which locale?
# Refer to locale -a
#
sub current_locale {
    if ($lh) {
	my $enc=$lh->maketext('lang_locale');
	return ($enc eq 'lang_locale'?'':$enc);
    } else {
	return undef;
    }
}

# ============================================================== Translate hash

sub texthash {
    my %hash=@_;
    foreach (keys %hash) {
	$hash{$_}=&mt($hash{$_});
    }
    return %hash;
}
# ======================================================== Re-route translation

sub clearreroutetrans {
    &reroutetrans();
    $reroute='';
}

# ======================================================== Re-route translation

sub reroutetrans {
    $ENV{'transreroute'}=1;
}

# ==================================================== End re-route translation
sub endreroutetrans {
    $ENV{'transreroute'}=0;
    if ($ENV{'environment.translator'}) {
	return $reroute;
    } else {
	return '';
    }
}

# ========= Get a handle (do not invoke in vain, leave this to access handlers)

sub get_language_handle {
    my $r=shift;
    $lh=Apache::localize->get_handle(&Apache::loncommon::preferred_languages);
    if (&Apache::lonnet::mod_perl_version == 1) {
	$r->content_languages([&current_language()]);
    }
###    setlocale(LC_ALL,&current_locale);
}

# ========================================================== Localize localtime

sub locallocaltime {
    my $thistime=shift;
    if ((&current_language=~/^en/) || (!$lh)) {
	return ''.localtime($thistime);
    } else {
	my $format=$lh->maketext('date_locale');
	if ($format eq 'date_locale') {
	    return ''.localtime($thistime);
	}
	my ($seconds,$minutes,$twentyfour,$day,$mon,$year,$wday,$yday,$isdst)=
	    localtime($thistime);
	my $month=(split(/\,/,$lh->maketext('date_months')))[$mon];
	my $weekday=(split(/\,/,$lh->maketext('date_days')))[$wday];
	if ($seconds<10) {
	    $seconds='0'.$seconds;
	}
	if ($minutes<10) {
	    $minutes='0'.$minutes;
	}
	$year+=1900;
	my $twelve=$twentyfour;
	my $ampm;
	if ($twelve>12) {
	    $twelve-=12;
	    $ampm=$lh->maketext('date_pm');
	} else {
	    $ampm=$lh->maketext('date_am');
	}
	foreach 
	('seconds','minutes','twentyfour','twelve','day','year',
	 'month','weekday','ampm') {
	    $format=~s/\$$_/eval('$'.$_)/gse;
	}
	return $format;
    }
}

# ==================== Normalize string (reduce fragility in the lexicon files)

# This normalizes a string to reduce fragility in the lexicon files of
# huge messages (such as are used by the helper), and allow useful
# formatting: reduce all consecutive whitespace to a single space,
# and remove all HTML
sub normalize_string {
    my $s = shift;
    $s =~ s/\s+/ /g;
    $s =~ s/<[^>]+>//g;
    return $s;
}
1;

__END__

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>