Cataly...Manual(3pm)
π NAME π
So this is Cataly...Manual(3pm) from the User Contributed Perl Documentation section, and it's the full glow-up guide for Catalyst::Plugin::I18N::Manual β (Draft) I18N and L10N with Catalyst and Template Toolkit. π¦
Yes bestie, the "(Draft)" is literally in the title, I'm not making that up. π
β¨ OUTLINE β¨
Here's the whole roadmap, and ngl it's giving "we're doing the entire journey in one sitting." π
π Prerequisites π
You need every single one of these first, no skips, no shortcuts:
perl>=5.8.0Catalyst>=5.33Catalyst::Plugin::I18N>=0.04Catalyst::Plugin::Unicode>=0.2Catlayst::View::TT&&Template-Toolkit>=2.14- GNU gettext utilities
- An editor that understands UTF-8 and Byte Order Mark (BOM)
not me preserving Catlayst::View::TT character for character even though it's typo'd β the source says it that way, so I say it that way. do not @ me π
πΈ Let's make an app πΈ
First move, literally just birth the whole project:
$ catalyst.pl MyApp
created "MyApp"
created "MyApp/script"
created "MyApp/lib"
created "MyApp/root"
created "MyApp/root/static"
created "MyApp/root/static/images"
created "MyApp/t"
created "MyApp/lib/MyApp"
created "MyApp/lib/MyApp/Model"
created "MyApp/lib/MyApp/View"
created "MyApp/lib/MyApp/Controller"
created "MyApp/lib/MyApp.pm"
created "MyApp/Makefile.PL"
created "MyApp/README"
created "MyApp/Changes"
created "MyApp/t/01app.t"
created "MyApp/t/02pod.t"
created "MyApp/t/03podcoverage.t"
created "MyApp/root/static/images/catalyst_logo.png"
created "MyApp/root/static/images/btn_120x50_built.png"
created "MyApp/root/static/images/btn_120x50_built_shadow.png"
created "MyApp/root/static/images/btn_120x50_powered.png"
created "MyApp/root/static/images/btn_120x50_powered_shadow.png"
created "MyApp/root/static/images/btn_88x31_built.png"
created "MyApp/root/static/images/btn_88x31_built_shadow.png"
created "MyApp/root/static/images/btn_88x31_powered.png"
created "MyApp/root/static/images/btn_88x31_powered_shadow.png"
created "MyApp/root/favicon.ico"
created "MyApp/script/myapp_cgi.pl"
created "MyApp/script/myapp_fastcgi.pl"
created "MyApp/script/myapp_server.pl"
created "MyApp/script/myapp_test.pl"
created "MyApp/script/myapp_create.pl"
Look at all those created lines, it's giving spring cleaning but make it β¨magicalβ¨.
π Time to edit the main module π
Hop in, cd over, and open that file:
$ cd MyApp
$ vim lib/MyApp.pm
use Catalyst qw/-Debug I18N Unicode/;
sub begin : Private {
my ( $self, $c ) = @_;
my $locale = $c->request->param('locale');
$c->response->headers->push_header( 'Vary' => 'Accept-Language' ); # hmm vary and param?
$c->languages( $locale ? [ $locale ] : undef );
}
sub default : Private {
my ( $self, $c ) = @_;
my $name = $c->request->param('name') || $c->loc('Guest');
$c->response->content_type('text/plain; charset=utf-8');
$c->response->body( $c->loc( 'Welcome [_1]!', $name ) );
}
Obsessed with begin doing the locale detective work in the shadows while default just serves the vibes. main character energy fr.
π§ Gettext time π§
Now we make a little home for our translations and scan everything:
$ mkdir lib/MyApp/I18N
$ xgettext.pl --output=lib/MyApp/I18N/messages.pot --directory=lib/
$ ls lib/MyApp/I18N/
messages.pot
Slay, we got a .pot. Now let's make a Swedish one because why not:
$ msginit --input=lib/MyApp/I18N/messages.pot --output=lib/MyApp/I18N/sv.po --locale=sv
Created lib/MyApp/I18N/sv.po.
π Edit the .po file π
Open it up and fill in the actual translations:
$ vim lib/MyApp/I18N/sv.po
"Content-Type: text/plain; charset=utf-8\n"
#: lib/MyApp.pm:50
msgid "Guest"
msgstr "GΓ€st"
#. ($name)
#: lib/MyApp.pm:54
msgid "Welcome %1!"
msgstr "VΓ€lkommen %1!"
Look at that charset line β charset=utf-8 is doing the heavy lifting so GΓ€st doesn't turn into abstract art. π¨
π₯ Run it π₯
Fire up the dev server and see the magic:
$ perl script/myapp_server.pl
[Fri Dec 2 03:52:45 2005] [catalyst] [debug] Debug messages enabled
[Fri Dec 2 03:52:47 2005] [catalyst] [debug] Loaded plugins:
.------------------------------------------------------------------------------.
| Catalyst::Plugin::I18N |
| Catalyst::Plugin::Unicode |
'------------------------------------------------------------------------------'
[Fri Dec 2 03:52:47 2005] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
[Fri Dec 2 03:52:47 2005] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
[Fri Dec 2 03:52:47 2005] [catalyst] [debug] Found home "/Users/chansen/MyApp"
[Fri Dec 2 03:52:48 2005] [catalyst] [debug] Initialized i18n "MyApp::I18N"
[Fri Dec 2 03:52:48 2005] [catalyst] [debug] Loaded Private actions:
.----------------------+----------------------------------------+--------------.
| Private | Class | Method |
+----------------------+----------------------------------------+--------------+
| /default | MyApp | default |
'----------------------+----------------------------------------+--------------'
[Fri Dec 2 03:52:48 2005] [catalyst] [info] MyApp powered by Catalyst 5.57
You can connect to your server at http://localhost:3000
# point your browser to http://localhost:3000/?name=Joe
# output should render:
VΓ€lkommen Joe!
It's giving multilingual and I am LIVING for it. Point your browser at it with ?name=Joe and it just... says hi in Swedish. Iconic.
π Change the string, resync π
Okay but what if we want different words? Edit the module:
$ vim lib/MyApp.pm
sub default : Private {
# ...
$c->response->body( $c->loc( 'Welcome to my homepage [_1]!', $name ) );
}
Then regenerate the template and merge it into the existing .po:
$ xgettext.pl --output=lib/MyApp/I18N/messages.pot --directory=lib/
$ msgmerge --update lib/MyApp/I18N/sv.po lib/MyApp/I18N/messages.pot
. done.
. done. β a tiny little victory message, we love to see it.
Then update the translation:
$ vim lib/MyApp/I18N/sv.po
#. ($name)
#: lib/MyApp.pm:54
msgid "Welcome to my homepage %1!"
msgstr "VΓ€lkommen till min hemsida %1!"
And run it again:
$ perl script/myapp_server.pl
# point your browser to http://localhost:3000/?name=Joe
# output should render:
VΓ€lkommen till min hemsida Joe!
Same server, new words, zero drama. We ate. π
π¦ Now add Template Toolkit π¦
Templates are where it's really at, so let's make a TT view:
$ perl script/myapp_create.pl view TT TT
exists "/Users/chansen/MyApp/script/../lib/MyApp/View"
exists "/Users/chansen/MyApp/script/../t"
created "/Users/chansen/MyApp/script/../lib/MyApp/View/TT.pm"
created "/Users/chansen/MyApp/script/../t/view_TT.t"
yes,existsreally does have a single leading space andcreateddoesn't. that's just how it is, bestie. π
Then wire it into your default action:
$ vim lib/MyApp.pm
sub default : Private {
my ( $self, $c ) = @_;
my $name = $c->request->param('name') || $c->loc('Guest');
$c->response->content_type('text/plain; charset=utf-8');
$c->stash(
name => $name,
template => 'test.tt'
);
$c->forward('MyApp::View::TT');
}
And make the template itself:
$ vim root/test.tt # Save file in UTF-8 with BOM
[% c.loc( 'Welcome to my place [_1]!', c.stash.name ) %]
Heads up: that comment is not a suggestion β save it in UTF-8 with BOM. For real for real. That's why the prerequisites list wanted an editor that understands BOM. π
Now rescan both lib/ and root/:
$ xgettext.pl --output=lib/MyApp/I18N/messages.pot --directory=lib/ --directory=root/
$ msgmerge --update lib/MyApp/I18N/sv.po lib/MyApp/I18N/messages.pot
. done.
Update the .po:
$ vim lib/MyApp/I18N/sv.po
#. (c.stash.name)
#: root/test.tt:1
msgid "Welcome to my place %1!"
msgstr "VΓ€lkommen till mitt stΓ€lle %1!"
And boot it up one more time:
$ perl script/myapp_server.pl
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Debug messages enabled
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Loaded plugins:
.------------------------------------------------------------------------------.
| Catalyst::Plugin::I18N |
| Catalyst::Plugin::Unicode |
'------------------------------------------------------------------------------'
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Found home "/Users/chansen/MyApp"
[Fri Dec 2 05:12:58 2005] [catalyst] [debug] Initialized i18n "MyApp::I18N"
[Fri Dec 2 05:12:59 2005] [catalyst] [debug] Loaded components:
.-------------------------------------------------------------------+----------.
| Class | Type |
+-------------------------------------------------------------------+----------+
| MyApp::View::TT | instance |
'-------------------------------------------------------------------+----------'
[Fri Dec 2 05:12:59 2005] [catalyst] [debug] Loaded Private actions:
.----------------------+----------------------------------------+--------------.
| Private | Class | Method |
+----------------------+----------------------------------------+--------------+
| /default | MyApp | default |
'----------------------+----------------------------------------+--------------'
[Fri Dec 2 05:12:59 2005] [catalyst] [info] MyApp powered by Catalyst 5.57
You can connect to your server at http://localhost:3000
# point your browser to http://localhost:3000/?name=Joe
# output should render:
VΓ€lkommen till mitt stΓ€lle Joe!
There it is. Templates + i18n + a whole Swedish homepage. Absolutely ate and left no crumbs. π
π INTRODUCTION π
πΈ INTERNATIONALIZATION πΈ
π CONTENT NEGOTIATION π
π Server-driven π
π¦ Agent-driven π¦
β¨ LOCALIZATION β¨
π₯ STAYING IN SYNC π₯
π TEMPLATE TOOLKIT π
and that's where part 1 leaves us, bestie β the tea continues in the next part, don't go anywhere π«Ά
πΈ RESOURCES πΈ
Okay bestie, this is the part where we hand you the entire link vault. Everything you need to actually do the i18n thing. Grab a snack. π
π Documentation
β¨ Definitions
- Internationalization and localization β
<http://en.wikipedia.org/wiki/Internationalization_and_localization> - Locale β
<http://en.wikipedia.org/wiki/Locale> - Byte Order Mark (BOM) β
<http://en.wikipedia.org/wiki/Byte_Order_Mark> - Character encoding β
<http://en.wikipedia.org/wiki/Character_encoding> - Collation β
<http://en.wikipedia.org/wiki/Collation> - Content Negotiation β
<http://en.wikipedia.org/wiki/Content_Negotiation> - Unicode β
<http://en.wikipedia.org/wiki/Unicode>
π§ Guides
- Guidelines, Checklists, and Resources β
<http://www.i18nguy.com/guidelines.html> - Localisation Guide β
<http://translate.sourceforge.net/wiki/guide/start>
πͺ Perl
- Perl Locale handling β
<http://search.cpan.org/dist/perl/pod/perllocale.pod> - Perl Unicode introduction β
<http://search.cpan.org/dist/perl/pod/perluniintro.pod> - Perl Unicode support β
<http://search.cpan.org/dist/perl/pod/perlunicode.pod> - Unicode-processing issues in Perl and how to cope with it β
<http://www.ahinea.com/en/tech/perl-unicode-struggle.html> - Web Localization in Perl β
<http://search.cpan.org/dist/Locale-Maketext-Lexicon/docs/webl10n.html> - Localization and Perl: gettext breaks, Maketext fixes β
<http://search.cpan.org/dist/Locale-Maketext/lib/Locale/Maketext/TPJ13.pod> - Lessons Learned with Perl and UTF-8 β
<http://www.justatheory.com/computers/programming/perl/utf8_trials.html> - UTF-8 and Perl (In Five Minutes) β Slides from a talk given by Mark Fowler.
<http://www.twoshortplanks.com/talks/utf8/perlandutf8.pdf> - Perl Loves UTF-8 β Slides from a talk given by Tom Insam.
<http://jerakeen.org/slush/talk-perl-loves-utf8> - Perl I18N Mailing List β
<http://lists.cpan.org/showlist.cgi?name=perl-i18n> - Perl Unicode Mailing List β
<http://lists.cpan.org/showlist.cgi?name=perl-unicode>
π Portals
- Google Directory - Computers > Software > Globalization β
<http://www.google.com/Top/Computers/Software/Globalization/> - Internationalization (I18N), Localization (L10N), Standards, and Amusements β
<http://www.i18nguy.com/>
π Standards
- RFC 2616 Hypertext Transfer Protocol -- HTTP/1.1 β
<http://www.w3.org/Protocols/rfc2616/rfc2616.html>- Section 12: Content Negotiation β
<http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12> - Section 13: Caching in HTTP β
<http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13> - Section 13.6: Caching Negotiated Responses β
<http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6>
- Section 12: Content Negotiation β
- RFC 3066 Tags for the Identification of Languages β
<http://www.faqs.org/rfcs/rfc3066.html>
πΈοΈ Web
- W3C Internationalization (I18N) Activity β
<http://www.w3.org/International/> - Authoring Techniques for XHTML & HTML Internationalization: Characters and Encodings 1.0 β
<http://www.w3.org/TR/i18n-html-tech-char/> - Authoring Techniques for XHTML & HTML Internationalization: Specifying the language of content 1.0 β
<http://www.w3.org/TR/i18n-html-tech-lang/>
ποΈ Locale Repositories
- Common Locale Data Repository (CLDR) β
<http://www.unicode.org/cldr/> - International Components for Unicode (ICU) β
<http://www-306.ibm.com/software/globalization/icu/index.jsp>
π¦ Modules
π€ Character Encoding, Collation and Normalization
- Encode β
<http://search.cpan.org/dist/Encode/> - Unicode::Collate β
<http://search.cpan.org/dist/Unicode-Collate/> - Unicode::Normalize β
<http://search.cpan.org/dist/Unicode-Normalize/>
π° Currency
- Locale::Currency::Format β
<http://search.cpan.org/dist/Locale-Currency-Format/> - Math::Currency β
<http://search.cpan.org/dist/Math-Currency/>
π Dates
- DateTime β
<http://search.cpan.org/dist/DateTime/> - DateTime::Locale β
<http://search.cpan.org/dist/DateTime-Locale/> - DateTime::TimeZone β
<http://search.cpan.org/dist/DateTime-TimeZone/>
π·οΈ Language Tags, Identification and Negotiation
- HTTP::Negotiate β
<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Negotiate.pm> - I18N::AcceptLanguage β
<http://search.cpan.org/dist/I18N-AcceptLanguage/> - I18N::LangTags β
<http://search.cpan.org/dist/I18N-LangTags/>and<http://search.cpan.org/dist/I18N-LangTags/lib/I18N/LangTags/Detect.pm>
π¬ Message Catalogs
- Locale::Maketext β
<http://search.cpan.org/dist/Locale-Maketext/>and<http://search.cpan.org/dist/Locale-Maketext/lib/Locale/Maketext/TPJ13.pod> - Locale::Maketext::Lexicon β
<http://search.cpan.org/dist/Locale-Maketext-Lexicon/>,<http://search.cpan.org/dist/Locale-Maketext-Lexicon/docs/webl10n.html>, and<http://search.cpan.org/dist/Locale-Maketext-Lexicon/script/xgettext.pl> - Locale::Maketext::Simple β Provides a simple interface to Locale::Maketext::Lexicon.
<http://search.cpan.org/dist/Locale-Maketext-Simple/> - libintl-perl β
<http://search.cpan.org/dist/libintl-perl/lib/Locale/Messages.pm>and<http://search.cpan.org/dist/libintl-perl/lib/Locale/TextDomain.pm>
π’ Numbers
- Number::Format β
<http://search.cpan.org/dist/Number-Format/>
π οΈ Tools
- GNU gettext utilities β
<http://www.gnu.org/software/gettext/>,<http://www.gnu.org/software/gettext/manual/html_chapter/gettext.html>, and<http://gnuwin32.sourceforge.net/packages/gettext.htm> - gtranslator β Translation tool for Gnome. Supports gettext catalogs.
<http://gtranslator.sourceforge.net/> - Ini Translator β Translation tool for Windows 98/Me/XP/2000. Supports several formats, including gettext catalogs.
<http://initranslator.sourceforge.net/> - KBabel β Translation tool for KDE. Supports gettext catalogs.
<http://i18n.kde.org/tools/kbabel/> - LocFactory Editor β Translation tool for Mac OS X. Supports sevral formats, including gettext catalogs.
<http://www.triplespin.com/en/products/locfactoryeditor.html> - poEdit β A cross-platform gettext catalogs editor.
<http://www.poedit.org/>
π AUTHOR
Christian Hansen "ch@ngmedia.com"
π COPYRIGHT
This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.
and that's the whole thing bestie, you made it to the end, so iconic of you πβ¨
this page is from perl v5.36.0, dated 2022-11-27 β go forth and localize, you absolute legend π π¦
π¦ where this page comes from
- debian bookworm: libcatalyst-plugin-i18n-perl 0.10-5 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libcatalyst-plugin-i18n-perl 0.10-5 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libcatalyst-plugin-i18n-perl 0.10-5 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libcatalyst-plugin-i18n-perl 0.10-5 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libcatalyst-plugin-i18n-perl 0.10-5 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms