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 $
0.03
This module provides a high-level interface to Perl message translation.
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.
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.
In case of change a project from Locale::Maketext or Locale::Maketext::Simple use an extended API Locale::TextDomain::OO::Maketext.
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.
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:
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::gettext_xs or Locale::gettext_pp.
An example for object binding is Locale::TextDomain::OO::MessagesStruct.
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.
Read the documentation of Locale::TextDoamin to learn more about the translation subroutines.
Run the examples of this distribution (folder example).
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
require Locale::TextDomain::OO;
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', ... );
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), );
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), ... );
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.
This method returns a code reference. Run this code reference to find the needed language from the environment and all the fallbacks.
my $code_ref = Locale::TextDomain::OO->get_default_language_detect();
or
my $code_ref = $loc->get_default_language_detect();
@langauges = $code_ref->();
or in scalar context typical for
local $ENV{LANGUAGE} = $code_ref->(); # result joined by :
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.
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 );
$nplurals = Locale::Text::Domain::OO->get_nplurals( 'nplurals=2; plural=n != 1;' # look at the po/mo file header );
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 );
$code_ref = Locale::Text::Domain::OO->get_function_ref_plural( 'nplurals=2; plural=n != 1;' # look at the po/mo file header );
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. | '----------------------------------------------------------------'
print $loc->__( 'Hello World!', );
print $loc->__x( 'Hello {name}!', name => 'Steffen', );
print $loc->__n( 'one file read', 'a lot of files read', $num_files, );
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.
print $loc->__p ( 'time', 'to', ); print $loc->__p ( 'destination', 'to', );
print $loc->__px ( 'destination', 'from {town_from} to {town_to}', town_from => 'Chemnitz', town_to => 'Erlangen', );
print $loc->__np ( 'maskulin', 'Dear friend', 'Dear friends', $friends, );
print $loc->__npx( 'maskulin', 'Mr. {name} has {num} book.', 'Mr. {name} has {num} books.', $books, name => $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. | '----------------------------------------------------------------'
The extractor looks for __('...') and has no problem with <$loc-N__('...')>>.
__('...')
<$loc-
This is the idea of the N-Methods.
$loc->N__('...');
Inside of this distribution is a directory named example. Read the file README there. Then run the *.pl files.
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, ...
none
Carp
Cwd
English
I18N::LangTags::Detect
I18N::LangTags
Safe
Locale::gettext_xs
Locale::gettext_pp
not known
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.
Steffen Winkler
Copyright (c) 2009, Steffen Winkler <steffenw at cpan.org>. All rights reserved.
<steffenw at cpan.org>
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Locale::TextDomain::OO, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Locale::TextDomain::OO
CPAN shell
perl -MCPAN -e shell install Locale::TextDomain::OO
For more information on module installation, please visit the detailed CPAN module installation guide.