NAME
Locale::TextDomain::OO - Perl OO Interface to Uniforum Message Translation
$Id: OO.pm 129 2009-11-30 09:21:28Z steffenw $
$HeadURL: https://perl-gettext-oo.svn.sourceforge.net/svnroot/perl-gettext-oo/trunk/lib/Locale/TextDomain/OO.pm $
VERSION
0.01
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,
1 book 2 books
but not before a number.
It is 1 book. These are 2 books.
There is no plural form without a nummber 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.
But there are a lot of modules around Locale::Maketext.
This is the reason for another module to have:
Endless (real: up to 6) plural forms controlled by the translater and not by the developer.
Named placeholders.
Locale::TextDomain::OO can bind gettext subroutines or gettext methods.
An example for binding subroutines is the default Locale::Messages.
An example for object binding is Locale::TextDomain::OO::MessagesStruct.
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
optinal 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 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 po-/mo-file header
);
or
$nplurals = Locale::Text::Domain::OO->get_nplurals(
'nplurals=2; plural=n != 1;' # look at 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 po-/mo-file header
);
or
$code_ref = Locale::Text::Domain::OO->get_function_ref_plural(
'nplurals=2; plural=n != 1;' # look at po-/mo-file header
);
Translating methods
How to bild 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 bild 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 is looking 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. Run this *.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
Safe
dynamic require
INCOMPATIBILITIES
not known
BUGS AND LIMITATIONS
none
SEE ALSO
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.