---
name: "Petal::I18N"
section: "3pm"
platform: "linux"
package: "libpetal-perl"
version: "2.26-2"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Petal::I18N"
---

# Petal::I18N(3pm)

Attempt at implementing ZPT I18N for Petal

## NAME

Petal::I18N - Attempt at implementing ZPT I18N for Petal

## SYNOPSIS

in your Perl code:

```
  use Petal;
  use Petal::TranslationService::Gettext;
  my $translation_service = new Petal::TranslationService::Gettext (
      locale_dir  => '/path/to/my/app/locale',
      target_lang => gimme_target_lang(),
  );
  my $template = new Petal (
      file => 'example.html',
      translation_service => $translation_service
  );
  # we want to internationalize to the h4x0rz 31337 l4nGu4g3z. w00t!
  my $translation_service = Petal::TranslationService::h4x0r->new();
  my $template = new Petal (
      file => 'silly_example.xhtml',
      translation_service => $ts,
  );
  print $template->process ();
```

## I18N Howto

### Preparing your templates:

Say your un-internationalized template looks like this:

```
  <html xmlns:tal="http://purl.org/petal/1.0/">
    <body>
      <img src="/images/my_logo.png"
           alt="the logo of our organisation" />
      <p>Hello,
         <span petal:content="user_name">Joe</span>.</p>
      <p>How are you today?</p>
    </body>
  </html>
```

You need to markup your template according to the ZPT I18N specification, which can be found at http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport

```
  <html xmlns:tal="http://purl.org/petal/1.0/"
        xmlns:i18n="http://xml.zope.org/namespaces/i18n"
        i18n:domain="my_app">
    <body>
      <img src="/images/my_logo.png"
           alt="the logo of our organisation"
           i18n:attributes="alt" />
      <p i18n:translate="">Hello, <span petal:content="user_name">Joe</span>.</p>
      <p i18n:translate="">How are you today?</p>
    </body>
  </html>
```

### Extracting I18N strings:

Once your templates are marked up properly, you will need to use a tool to extract the I18N strings into .pot (po template) files. To my knowledge you can use i18ndude (standalone python executable), i18nextract.py (part of Zope 3), or I18NFool.

I use i18ndude to find strings which are not marked up properly with i18n:translate attributes and I18NFool for extracting strings and managing .po files.

Assuming you're using i18nfool:

```
  mkdir -p /path/to/my/app/locale
  cd /path/to/my/app/locale
  i18nfool-extract /path/to/my/template/example.html
  mkdir en
  mkdir fr
  mkdir es
  i18nfool-update
```

Then you translate the .po files into their respective target languages. When that's done, you type:

```
  cd /path/to/my/app/locale
  i18nfool-build
```

And it builds all the .mo files.

### Making your application use a Gettext translation service:

Previously you might have had:

```
  use Petal;
  # lotsa code here
  my $template = Petal->new ('example.html');
```

This needs to become:

```
  use Petal;
  use Petal::TranslationService::Gettext;
  # lotsa code here
  my $template = Petal->new ('example.html');
  $template->{translation_service} = Petal::TranslationService::Gettext->new (
      locale_dir  => '/path/to/my/app/locale',
      target_lang => gimme_language_code(),
  );
```

Where **gimme\_language\_code()** returns a language code depending on LC\_LANG, content-negotiation, config-file, or whatever mechanism you are using to decide which language is desired.

### And then?

And then that's it! Your application should be easily internationalizable. There are a few traps / gotchas thought, which are described below.

## BUGS, TRAPS, GOTCHAS and other niceties

### Translation Phase

The translation step takes place ONLY ONCE THE TEMPLATE HAS BEEN PROCESSED.

So if you have:

```
  <p i18n:translate="">Hello,
    <span i18n:name="user_login" tal:replace="self/user_login">Joe</span>
  </p>
```

It most likely will not work because the tal:replace would remove the \<span\> tag and also the i18n:name in the process.

This means that instead of receiving something such as:

```
  Hello, ${user_login}
```

The translation service would receive:

```
  Hello, Fred Flintstone
```

Or

```
  Hello, Joe SixPack
```

etc.

To fix this issue, use tal:content instead of tal:replace and leave the span and its i18n:name attribute.

### Character sets

I haven't worried too much about them (yet) so if you run into trouble join the Petal mailing list and we'll try to fix any issues together.

### Limitations

At the moment, Petal::I18N supports the following constructs:

- xmlns:i18n="http://xml.zope.org/namespaces/i18n"

  - i18n:translate

  - i18n:domain

  - i18n:name

  - i18n:attribute

  It does \*NOT\* (well, not yet) support i18n:source, i18n:target or i18n:data.
