.==-. .-==.
\()8`-._ `. .' _.-'8()/
(88" ::. \./ .:: "88)
\_.'`-::::.(#).::::-'`._/
`._... .q(_)p. ..._.'
""-..-'|=|`-..-""
.""' .'|=|`. `"".
,':8(o)./|=|\.(o)8:`.
(O :8 ::/ \_/ \:: 8: O)
\O `::/ \::' O/
""--' `--"" hjw
Lexicon Translator Plugins
.-==.
.' _.-'8()/
\./ .:: "88)
(#).::::-'`._/
(_)p. ..._.'
|=|`-..-""
|=|`. `"".
|=|\.(o)8:`.
\_/ \:: 8: O)
\::' O/
`--"" hjw
Lexicon Plugins
... = Locale::TextDomain::OO->instance(
plugins => [ ... ],
);
... = Locale::TextDomain::OO->new(
plugins => [ ... ],
language => '...', # set on different ways
# normally note here
category => '...', # see also loc_c
domain => '...', # see also loc_d
project => '...', # to create multiple singletons
filter => sub { ... }, # running after translation
);
Ends with something like
MyProject::I18N->instance;
Escape the whole translation
#. { search_argument => $code // q{} },
#: lib/.../Appointments.pm:296
#: lib/.../Appointments.pm:334
msgid "No results for [{search_argument}]"
msgstr "Keine Ergebnisse für [{search_argument}] gefunden"
Easy to prevent broken HTML
#: lib/.../Survey.pm:57 msgid "Write a <a>experience review</a> now" msgstr "Schreiben Sie jetzt einen <a>Erlebnis-Bericht</a>"
Escape placeholders
#. experience => $event->name
#: lib/.../Survey.pm:53
msgid ""
"Did you already attend your experience"
" <b>{experience :html}</b>?"
msgstr ""
"Haben Sie schon an Ihrem Erlebnis"
" <b>{experience :html}</b> teilgenommen?"
Except simple text for easier translation
#. end => $voucher_end, start => $start_param,
#: lib/.../Create.pm:100
msgid ""
"The voucher end date [{end :date}]"
" expires before the chosen appointment [{start :date}]."
msgstr ""
"Das Gutschein-Enddatum [{end :date}]"
" läuft vor dem gewählten Termin [{start :date}] ab."
package MyProject::I18N;
sub new {
my $ltdoo = Locale::TextDomain::OO->new(
plugins => [ qw(
Language::LanguageOfLanguages
Expand::Gettext::Loc
Expand::Maketext::Loc
) ],
logger => sub {
my ($message, $arg_ref) = @_;
my $type = $arg_ref->{type};
MyLogger->$type($message);
return;
},
filter => sub {
my ($self, $string_ref) = @_;
# Maketext: remove escape char ~ from ~, [ and ]
${$string_ref} =~ s{ [~] ( [~\[\]] ) }{$1}xmsg;
return;
},
);
for ( $ltdoo->expand_gettext_loc, $ltdoo->expand_maketext_loc ) {
$_->modifier_code(
sub {
my ( $value, $attribute ) = @_;
return __PACKAGE__->loc_format(
$ltdoo, $value, $attribute,
);
},
);
};
return $ltdoo;
}
sub loc_format {
# numf, numf0 .. numfN, numf00 .. numf0N
... format numeric placeholder
# nump, nump0 .. numpN, nump00 .. nump0N, numpf
# numpEUR, nump0EUR .. numpNEUR, nump00EUR .. nump0NEUR, numpfEUR
... format price placeholder
# html, javascript
... run escape
}
...->loc_nx( q{{number :numf2} foo}, q{{number :numf2} foo's}, # switch between plural forms number => ...->loc_round($number, ':numf2'), );
sub loc_round {
# numf, numf0 .. numfN, numf00 .. numf0N
... format numeric placeholder
# nump, nump0 .. numpN, nump00 .. nump0N, numpf
# numpEUR, nump0EUR .. numpNEUR, nump00EUR .. nump0NEUR, numpfEUR
... format price placeholder
}
Some lexicon key parts are used during translation
Split multiple projects in lexicon hash
Some short helpers
my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys ->instance; my $jlk = fun ($language) { $key_util->join_lexicon_key({ language => $language }); }; my $jlk_c = fun ($language, $category) { $key_util->join_lexicon_key({ category => $category, language => $language }); };
Locale::TextDomain::OO::Lexicon::File::MO
->new
->lexicon_ref({
search_dirs => [ MyConfig->i18n_path ],
data => [
$jlk->( q{*} ) => '*.mo',
merge_lexicon => $jlk->('de'), $jlk->('de-at')
=> $jlk->('de-at'),
merge_lexicon => $jlk->('de'), $jlk->('de-ch')
=> $jlk->('de-ch'),
],
decode => 1,
});
my $lexicon_po = Locale::TextDomain::OO::Lexicon::File::PO->new;
my @children = MyConfig
->i18n_path
->children( __PACKAGE__->language_cached_regex );
for my $child (@children) {
my $category = $child->relative( MyConfig->i18n_path )->stringify;
$lexicon_po
->lexicon_ref({
search_dirs => [ $child ],
data => [ $jlk_c->( q{*}, $category ) => '*.po' ],
gettext_to_maketext
=> 1,
});
}
my @mappings = (
# hfh lexicons of version 0.40056
{ hfh => 'de_de', language => 'de', plural_forms => 'nplurals=2; plural=(n != 1);' },
{ hfh => 'en_us', language => 'en', plural_forms => 'nplurals=2; plural=(n != 1);' },
{ hfh => 'ru_ru', language => 'ru', plural_forms => 'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);' },
# map non hfh languages to hfh en because used in project
{ hfh => 'en_us', language => 'cs', plural_forms => 'nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;' },
{ hfh => 'en_us', language => 'es', plural_forms => 'nplurals=2; plural=(n != 1);' },
{ hfh => 'en_us', language => 'fr', plural_forms => 'nplurals=2; plural=(n > 1);' },
);
my $package = load_class(
"HTML::FormHandler::I18N::$map_ref->{hfh}",
);
my %package_lexicon = %{"${package}::Lexicon"};
delete $package_lexicon{_AUTO};
$lexicon_of{
$jlk_c->(
$map_ref->{language},
'HTML_FormHandler',
)
} = [ ... ]; # header and messages
Locale::TextDomain::OO::Lexicon::Hash ->new ->lexicon_ref(\%lexicon_of);
my $lexicon = Locale::TextDomain::OO::Singleton::Lexicon
->instance;
$lexicon
->merge_lexicon(
$jlk_c->('de', 'HTML_FormHandler'), $jlk->('de-at')
=> $jlk_c->('de-at', 'HTML_FormHandler'),
)
->merge_lexicon(
$jlk_c->('de', 'HTML_FormHandler'), $jlk->('de-ch')
=> $jlk_c->('de-ch', 'HTML_FormHandler'),
);