At our company, we have a single app available in multiple locales. We use
Mason, but we don't include any content in the components. Since it's a one
size fits all app, we keep all of our content (all UTF8) in versioned XML files
as strings; each string having a unique string id as an XML attribute. We have
separate HTML templates that use HTML::Template to process the string files for
static content substitution, as well as for dynamic data. This way, we have
single Mason components that get cached, and we call HTML::Template at
run-time, to choose the proper templates from the following type of directory
structure:
.../html/enus (English, US)
/engb (Queen's English, UK)
/svse (Swedish, Sweden)
etc.
Because we keep our static content in XML files, we can pre-build all HTML
templates (all sites can share the same templates) or we can do substitution
dynamically at run-time. We only need to make unique templates for UI that is
unique to a locale (i.e. registration fields, etc.). Also, we can edit only
the string id's in the XML files we need, and check in new versions as changes
or additions arise. The XML format works well with our L10n group, as their
tools just slurp them in, and they can edit away. Since we can dynamically
build our templates at run-time, we can also offer special template content
that displays string ID's for each string shown, with respect to the XML string
file it came from; this allows the LQA folks to quickly identify incorrect
strings in context in our app, and go directly to the proper string in their
L10n tools to edit it. (Of course, we pre-build the localized HTML before
releases to production, though, better performance). How we know w
hich locale templates to use is based off the domain of the incoming request.
But, the way we designed it, any user could view our site in any of the locales
we support, at any time.
Basically, we are using HTML::Mason and HTML::Template out-of-the-box for this,
no customization needed. Not sure if this helps at all, but it works well for
us. My $0.02 ...
- Jeff
----- Original Message ----
From: John Williams <[EMAIL PROTECTED]>
To: Kovacs Baldvin <[EMAIL PROTECTED]>
Cc: [email protected]
Sent: Tuesday, January 9, 2007 9:53:41 AM
Subject: Re: [Mason] l10n efficiency
On Tue, 9 Jan 2007, Kovacs Baldvin wrote:
> I am wondering if a different approach would be possible: why don't we
> hack the mason compiler to compile not just .obj files from the
> templates, but .en.obj, .fr.obj, .de.obj, ... When a component is to be
> run, then the appropriate .obj file is taken, and would run the same
> speed as there were no internationalization would be in place.
The way I do it is to override Mason's Resolver class. The language is
part of the URL, and my Resolver actually reads the html file from a
common directory. This way there is only one copy of the untranslated
mason source, but the mason cache has one copy for each language.
We use <trans key=xyzzy> tags to delimit the translatable text. Mason's
"<% %>" tags are replaced by "{1}" in the translation database, so they
can be reordered. (In my experience, even that much flexibility confuses
many contractual translators.)
I cannot share my company's translation code, but here is the get_info
function from our Resolver subclass. It just a modified version
of the code from HTML::Mason::Resolver::File. Modifying this use to
Maketext is left as an exercise for the reader.
sub get_info {
my ($self, $path) = @_;
# get the language handle
my $tr = TNI::Translation->new(
comp_root => $self->comp_root,
path => $path,
);
# language is determined from the URL
my $language = $tr->language;
# when the translation database was last modified
my $modified = $tr->domain_modified( unix=>1 ) || 0;
# find the untranslated file
my $english = $path;
$english =~ s{//+}{/}g;
$english =~ s{^/([^/]*?)/\Q$language\E/}{/default/english/} if
$language;
foreach my $pair ($self->comp_root_array) {
my $fname = File::Spec->canonpath( File::Spec->catfile(
$pair->[1], $path ) );
my $srcfile = File::Spec->canonpath( File::Spec->catfile(
$pair->[1], $english ) );
next unless -f $srcfile;
my $filemodified = (stat _)[9];
$modified = $filemodified if $filemodified > $modified;
my $key = $pair->[0];
my $base = $key eq 'MAIN' ? '' : "/$key";
$key = undef if $key eq 'MAIN';
return
HTML::Mason::ComponentSource->new
( friendly_name => $fname,
comp_id => "$base$path",
last_modified => $modified,
comp_path => $path,
comp_class =>
'HTML::Mason::Component::FileBased',
extra => { comp_root => $key },
#source_callback => sub {
read_file_ref($srcfile) },
source_callback => sub {
# read the source file and translate
TNI::Translation::Parse::HTML->new( tr=>$tr
)->translate_page_ref(read_file_ref($srcfile));
},
);
}
# see if path corresponds to real filesystem path, a common new user
mistake
my $fs_path = File::Spec->catfile( split /\//, $path );
if ( defined $fs_path && -e $fs_path )
{
warn "Your component path ($path) matches a real file on disk
($fs_path). Have you read about the component root in the Administrator's
Manual (HTML::Mason::Admin)?";
}
return;
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Mason-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mason-users
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Mason-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mason-users