.==-. .-==. \()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'), );