I18N with XSLT and what Perl has got to do with it‎

Michael Kröll <[email protected]>

XSLT and I18N


XSLT and I18N – Approaches

XSLT and I18N – Example

The XML file (excerpts)
  <i key="Frankfurter" xml:lang="de-at">Frankfurter</i>
  <i key="Frankfurter" xml:lang="de-de">Wiener</i>
  <i key="Frankfurter" xml:lang="de-ch">Wienerli</i>
The XSL file (excerpts)
<xsl:param name="current_lang" select="'en'"/>
<xsl:variable name="i18n" select="document('i18n.xml')/i18n"/>
<func:function name="i18n:loc">
  <xsl:param name="key" />
  <xsl:param name="lang" select="$current_lang" />
  <func:result select="$i18n/i[@key=$key and lang($current_lang)]"/>
<xsl:value-of select="i18n:loc('Frankfurter')"/> mit Senf.

XSLT and I18N

“…XML based catalogs? But I want to re-use my PO files from the back-end!”

Perl to the rescue!

God: “We hacked most of it together with Perl”.
XKCD Lisp Perl God

Two things needed

  1. I18N Perl class for your app
    (e.g. based on Locale::Maketext::Simple or directly Locale::Maketext::Lexicon)
  2. Register localisation methods as extension functions with XML::LibXSLT

Example I18N Perl class – MyApp::I18N

Example Perl EXSLT function (excerpt)

my $i18n = MyApp::I18N->new( lang => $lang );
my $registeredfuncs = [{
        uri  => 'http://myapp.tld/i18n',
        name => 'loc',
        code => sub {
                    my ( $template, @param ) = @_;
                    return $i18n->loc( $template, @param );
        uri  => 'http://myapp.tld/i18n',
        name => 'locfrag',
        code => sub {
                    my $fragment = $parser->parse_balanced_chunk( 
                        $i18n->loc( $template, @param ) );
                    return $fragment->find('text()|*');

Example Perl EXSLT function (II)

foreach my $function ( @{$registeredfuncs} ) {

Example Usage (excerpt)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0" xmlns:i18n="http://myapp.tld/i18n"
<xsl:value-of select="i18n:loc('Frankfurter')"/>
  select="i18n:loc("Do you want to have
                   more '[_1]'?", SAUSAGENAME)"/>
    'For some reason there is a linebreak <br/> here')"/>

Drawbacks and Caveats