The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Locale::TextDomain::OO - Perl OO Interface to Uniforum Message Translation

$Id: OO.pm 164 2009-12-07 21:29:45Z steffenw $

$HeadURL: https://perl-gettext-oo.svn.sourceforge.net/svnroot/perl-gettext-oo/trunk/lib/Locale/TextDomain/OO.pm $

VERSION

0.03

DESCRIPTION

This module provides a high-level interface to Perl message translation.

Why a new module?

This module is very similar to Locale::TextDomain.

The most important problem of Locale::TextDomain is the functional interface and consequently the use of the caller to figure out the text domain. That is why is not possible to wrap Locale::TextDomain functions into a new package.

Locale::TextDomain::OO has a flexible object oriented interface.

Why to write a wrapper?

Locale::TextDomain depends on Locale::Messages and Locale::Messages depends on gettext mo files. This is a very good idea to do this. It is a standard.

But if the data are not saved in mo files and the project is not a new project, how to bind a database or anything else to the Locale::TextDomain API?

Now it is possible to change the source of data.

Why to inherit?

In case of change a project from Locale::Maketext or Locale::Maketext::Simple use an extended API Locale::TextDomain::OO::Maketext.

Why bind late to a more simple functional interface?

Locale::TextDomain::OO::FunctionalInterface is a wrapper to have functions like Locale::TextDomain for the application interface and all the benefit from the binded object too.

Do not follow the dead end of Locale::Maketext!

What is the problem of?

  • Locale::Maketext allows 2 plural forms (and zero) only. This is changable, but the developer has to control the plural forms. He is not an omniscient translator.

  • 'quant' inside a phrase is the end of the automatic translation because quant is an 'or'-construct.

        begin of phrase [quant,_1,singular,plural,zero] end of phrase
  • The plural form is allowed after a number, followed by a whitespace, not a non-breaking whitespace.

        1 book
        2 books

    A plural form can not be before a number.

        It is 1 book.
        These are 2 books.
  • There is no plural form without a number in the phrase.

        I like this book.
        I like these books.
  • Placeholders are numbered serially. It is difficult to translate this because the sense of the phrase could be lost.

        [_1] is a [_2] in [_3].
    
        Erlangen is a town in Bavaria.
  • But there are a lot of modules around Locale::Maketext.

This is the reason for another module to have:

What is the difference?

As default this module calls the subroutines like module Locale::Messages.

This behaviour is changeable. Choose a functional or object oriented module. Locale::Messages is an functional module. Locale::TextDomain::OO::MessagesStruct is an object oriented module.

Locale::TextDomain::OO::MessagesStruct implements the idea to read the full data into a data structure for fast access.

More informations

Read the documentation of Locale::TextDoamin to learn more about the translation subroutines.

Run the examples of this distribution (folder example).

Overview

      Application calls           Application calls         Application calls
       TextDomain subs     .------ TextDomain subs           method maketext
          (the goal)       |     and Maketext methods -.     (the beginning)
              |            |       (the changeover)    |                |
              |            |                           |                |
              |            |                           '------------.   |
              |            v                                        |   |
              |   .---------------------------------------------.   |   |
              |   |             functional interface            |   |   |
              |   |---------------------------------------------|   |   |
              |   | Locale::TextDomain::OO::FunctionalInterface |   |   |
              |   |---------------------------------------------|   |   |
              |   |                 calls methods               |   |   |
              |   `---------------------------------------------'   |   |
              |                          |                          |   |
              |                          v                          v   v
              |            .------------------------------------------------.
              |            |               OO interface like                |
              |            |            Locale::Maketext::Simple            |
              |            |                      and (!)                   |
              |            |             Locale::TextDomain::OO             |
              |            |------------------------------------------------|
              |            |        Locale::TextDomain::OO::Maketext        |
              |            `------------------------------------------------'
              |                    |
              v                    v
          .----------------------------.
          |       interface like       |
          |     Locale::TextDomain     |
          |----------------------------|
          |   Locale::TextDomain::OO   |
          `----------------------------'
              |                    |
              v                    v
 .-------------------------.   .----------------------------------------.
 | Locale::gettext_(xs|pp) |   | Locale::TextDomain::OO::MessagesStruct |
 |      (the default)      |   |            (a possibility)             |
 `-------------------------'   `----------------------------------------'
           |                                  |
           |                                  v
           |                        .-------------------.
           |                        |    data struct    |
           |                        |-------------------|
           |                        |  |                |
           |                        |  +--[text domain] |
           |                        |     |             |
           |                        |     `--[...]      |
           |                        `-------------------'
           |                          ^               ^
           |                          |               |
           |      .------------------------.          |
           |      |       build using      |   .-------------.
           |      |   po extrction tools   |   | build using |
           |      |      like DBD::PO      |   |     DBI     |
           |      | or DBD::PO::Locale::PO |   `-------------'
           |      `------------------------'          ^
           |                   ^                      |
           v                   |                 _____|_____
    .----------.         .----------.           /_ _ _ _ _ _\
    | mo files |-.       | po files |-.         |           |
    `----------' |       `----------' |         | Database  |
      `----------'         `----------'         `-----------'
           ^                   ^                      ^
           |                   |                      |
      build using         build using            existing data
     gettext tools       gettext tools

SYNOPSIS

    require Locale::TextDomain::OO;

SUBROUTINES/METHODS

method new

optional parameter text_domain

Set the default text domian __PACKAGE__.

    my $loc = Locale::TextDoamin::OO->new(
        ...
    );

Set the text domain.

    my $loc = Locale::TextDoamin::OO->new(
        ...
        text_domain => 'exapmle',
        ...
    );

optional parameter search_dirs

Set the search dirs.

    my $loc = Locale::TextDoamin::OO->new(
        ...
        search_dirs => \@local_dirs,
        ...
    );

The default for the search_dirs is:

    my @locale_dirs = map {
        -d "$_/LocaleData"
        ? "$_/LocaleData"
        : ();
    } (
        @INC,
        qw(/usr/share/locale /usr/local/share/locale),
    );

optional parameter gettext_package or alternative gettext_object

Note, that the default of gettest_package is Locale::gettext_xs or Locale::gettext_pp. This package has to implement the subroutines 'dgettext', 'dngettext', 'dpgettext', 'dnpgettext' and can implement the subroutine 'bindtextdomain'.

    my $loc = Locale::TextDoamin::OO->new(
        gettext_package => 'Package::With::Subroutines',
        ...
    );

Or alternative the package which has to implement the methods 'dgettext', 'dngettext', 'dpgettext', 'dnpgettext'.

    my $loc = Locale::TextDoamin::OO->new(
        gettext_object => Locale::TextDomain::OO::MessagesStruct->new(\my %struct),
        ...
    );

optional parameter language_detect

Describe as code, how to detect the language. This example code describes the default in list context.

    my $loc = Locale::TextDoamin::OO->new(
        ...
        language_detect => sub {
           my @languages_want = I18N::LangTags::Detect::detect();
           my @languages_all  = implicate_supers(@languages_want);
           return @languages_all, panic_languages(@languages_all);
        },
        ...
    );

Read I18N::LangTags, panic_languages for more informations.

method get_default_language_detect

This method returns a code reference. Run this code reference to find the needed language from the environment and all the fallbacks.

get the code reference

    my $code_ref = Locale::TextDomain::OO->get_default_language_detect();

or

    my $code_ref = $loc->get_default_language_detect();

run the code in list context

    @langauges = $code_ref->();

or in scalar context typical for

    local $ENV{LANGUAGE} = $code_ref->(); # result joined by :

method get_file_path

    my $file_suffix = '.mo';
    my $file_path   = $loc->get_file_path($text_domain, $file_suffix);

If a file based database system not exists, create an extra file system. Write down for which language and which text domain a database exists. Instead of an "$text_domain$suffix" database file create some empty dummy files.

If possible, extract this informations automaticly from the database.

Than the method get_file_path checks the wanted languages and matches the existing langauges.

    my ($dir, $language) = $loc->get_file_path($text_domain, $file_suffix);

Another way to use this module with a none file based database system is to implement the language selection self.

object or class method get_nplurals

How many plurals has the translation? This is one-time interesting to read the translation data.

    $nplurals = $self->get_nplurals(
        'nplurals=2; plural=n != 1;' # look at the po/mo file header
    );

or

    $nplurals = Locale::Text::Domain::OO->get_nplurals(
        'nplurals=2; plural=n != 1;' # look at the po/mo file header
    );

object or class method get_function_ref_plural

Which plural form sould be used? The code runs during every plural tranlation.

    $code_ref = $self->get_function_ref_plural(
        'nplurals=2; plural=n != 1;' # look at the po/mo file header
    );

or

    $code_ref = Locale::Text::Domain::OO->get_function_ref_plural(
        'nplurals=2; plural=n != 1;' # look at the po/mo file header
    );

Translating methods

How to build the method name?

Use __ and append this with 'n', 'p' and/or 'x' in alphabetic order.

 .----------------------------------------------------------------.
 | Snippet | Description                                          |
 |---------+------------------------------------------------------|
 | __      | Special marked for extraction.                       |
 | x       | Last parameters are the hash for named placeholders. |
 | n       | Using plural forms.                                  |
 | p       | Context is the first parameter.                      |
 '----------------------------------------------------------------'

__ Translate only

    print $loc->__(
        'Hello World!',
    );

__x Named placeholders

    print $loc->__x(
        'Hello {name}!',
        name => 'Steffen',
    );

__n Plural

    print $loc->__n(
        'one file read',
        'a lot of files read',
        $num_files,
    );

__nx Plural and named placeholders

    print $loc->__nx(
        'one file read',
        '{num} files read',
        $num_files,
        num => $num_files,
    );

The sub __xn is the same like sub __nx at Locale::TextDomain.

Method __xn is not implemented because it is the same like method __nx.

__p Context

    print $loc->__p (
        'time',
        'to',
    );

    print $loc->__p (
        'destination',
        'to',
    );

__px Context and named placeholders

    print $loc->__px (
        'destination',
        'from {town_from} to {town_to}',
        town_from => 'Chemnitz',
        town_to   => 'Erlangen',
    );

__np Context and plural

    print $loc->__np (
        'maskulin',
        'Dear friend',
        'Dear friends',
        $friends,
    );

__npx Context, plural and named placeholders

    print $loc->__npx(
        'maskulin',
        'Mr. {name} has {num} book.',
        'Mr. {name} has {num} books.',
        $books,
        name => $name,
    );

Methods to mark the translation for extraction only

How to build the method name?

Use N__ and append this with 'n', 'p' and/or 'x' in alphabetic order.

 .----------------------------------------------------------------.
 | Snippet | Description                                          |
 |---------+------------------------------------------------------|
 | N__     | Special marked for extraction.                       |
 | x       | Last parameters are the hash for named placeholders. |
 | n       | Using plural forms.                                  |
 | p       | Context is the first parameter.                      |
 '----------------------------------------------------------------'

N__, N__x, N__n, N__nx, N__p, N__px, N__np, N__npx

The extractor looks for __('...') and has no problem with <$loc-N__('...')>>.

This is the idea of the N-Methods.

    $loc->N__('...');

EXAMPLE

Inside of this distribution is a directory named example. Read the file README there. Then run the *.pl files.

DIAGNOSTICS

Error message in case of unknown parameters.

 Unknown parameter: ...

Error message during load of the implementation package.

 Can't locate ...

Error message during load of the default implementation package.

 gettext_xs_version ... is to old.

Error message at calculation plural forms.

 Plural-Forms are not defined

 Code of Plural-Forms ... is not safe, ...

 Code ... is not safe, ...

CONFIGURATION AND ENVIRONMENT

none

DEPENDENCIES

Carp

Cwd

English

I18N::LangTags::Detect

I18N::LangTags

Safe

dynamic require

Locale::gettext_xs

Locale::gettext_pp

INCOMPATIBILITIES

not known

BUGS AND LIMITATIONS

none

SEE ALSO

Locale::TextDoamin

Locale::Messages

http://www.gnu.org/software/gettext/manual/gettext.html

http://en.wikipedia.org/wiki/Gettext

http://translate.sourceforge.net/wiki/l10n/pluralforms

http://rassie.org/archives/247 The choice of the right module for the translation.

AUTHOR

Steffen Winkler

LICENSE AND COPYRIGHT

Copyright (c) 2009, Steffen Winkler <steffenw at cpan.org>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.