Templa...Gettext(3pm)
π NAME π
Template::Plugin::Gettext β Gettext Support For the Template Toolkit, Version 2 π¦
β¨ SYNOPSIS β¨
okay bestie, first things first: you gotta load the plug-in inside your templates. like this:
[% USE Gettext('com.textdomain.my', 'fr', 'utf-8', 'DIRECTORIES'...) %]
[% Gettext.gettext('Hello, world!') %]
[% 'Hello, world!' | gettext %]
orrrr you can alias Gettext if typing the whole thing is giving carpal tunnel π
[% USE gtx = Gettext('com.textdomain.my', 'fr', 'utf-8', 'DIRECTORIES'...) %]
[% gtx.gettext('Hello, world!') %]
you can also go the method-invocation route:
[% Gettext.gettext("Hello, world!") %]
[% Gettext.xgettext("Hello, {name}!", name => 'John Doe') %]
or use filters (no prefix needed, we love a low-effort moment):
[% FILTER gettext %]
Hello, world!
[% END %]
[% 'Hello, world!' | gettext %]
[% FILTER xgettext(name => 'John Doe') %]
Hello, {name}!
[% END %]
and girl, you have a multitude of methods available, it's genuinely iconic:
[% gtx.gettext("Hello, user!") %]
[% gtx.xgettext("Hello, {user}!", user => 'John Doe') %]
[% gtx.ngettext("One document deleted.",
"Multiple documents deleted."),
42) %]
[% gtx.nxgettext("One document deleted.",
"{num} documents deleted."),
42,
num => 42) %]
[% gtx.npgettext("context..."
"One document deleted.",
"Multiple documents deleted."),
42) %]
[% gtx.npxgettext("context...",
"One document deleted.",
"{num} documents deleted."),
42,
num => 42) %]
πΈ DESCRIPTION πΈ
so basically, the Template::Plugin::Gettext plug-in makes the GNU gettext API (that's <https://www.gnu.org/software/gettext/>, no cap) available to your documents that are using the Template Toolkit version 2 (<http://template-toolkit.org/>). β¨
if you want the whole big picture β the full vibe, the lore, and the recommended tool-chain β go peek at <https://github.com/gflohr/Template-Plugin-Gettext>. it's giving documentation main character energy π«Ά
bestie, that's only the beginning of the page β there's way more coming, don't go anywhere π
π FUNCTIONS π
okay bestie, these are the methods that actually produce translatable content. all of them. no skips. let's go β¨
[% gtx.gettext(STRING) %]β grabs the translation for STRING. that's the whole thing, that's the vibe π[% gtx.xgettext(STRING, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2, ...) %]β gets the translation for a string with placeholders and interpolates values into it. placeholders have the format<{PLACEHOLDER}>. and if you want a literal left curly brace, there's a little hack for that:
[% gtx.xgettext("String with {LBRACE}PLACEHOLDERS{RBRACE}",
LBRACE => "{", RBRACE => "}") %]
[% gtx.pgettext(CONTEXT, STRING) %]β retrieves the translation for STRING in context CONTEXT. you use message context to disambiguate identical strings that need different translations depending on context. here's the example that explains everything:
[% gtx.gettext("State: ") %]
[% gtx.gettext("Open")] | [% gtx.gettext("Close") %]
[% gtx.gettext("Menu:") %]
[% gtx.pgettext("menu", "Open")]
[% gtx.gettext("Save")]
[% gtx.gettext("Save As")]
[% gtx.pgettext("menu", "Close")]
the strings "Open" and "Close" in line 2 are adjectives. as menu entries they're verb forms and will have a different translation in many languages.
in doubt: only use contexts if one of your translators complains about a message having multiple meanings. fr fr π
[% gtx.pxgettext(CONTEXT, STRING, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]β get the translation for STRING with placeholders in context CONTEXT. it's a mashup ofxgettext()andpgettext()up above. iconic behavior honestly.[% gtx.nxgettext(SINGULAR, PLURAL, COUNT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]β retrieves the translation for the string with singular form SINGULAR and plural form PLURAL, both possibly containing placeholders. the correct form gets picked based on the third argument, COUNT.
example:
[% gtx.nxgettext("One document deleted",
"{num} documents deleted"),
count,
num => count) %]
in English this produces "42 documents deleted" if the variable count has the value 42. and it produces "One document deleted" if the variable count has the value 1. cute right?
in other languages the rules for plural forms can be a lot simpler (chinese, for example, which has no plural) or a lot more complicated (russian with two, or slovenian with even 3 plural forms). using ngettext() gives your translators the chance to provide syntactically correct translations for these cases. give them that chance π«Ά
[% gtx.npxgettext(CONTEXT, SINGULAR, PLURAL, COUNT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]β putting it all together: for message context CONTEXT, the translation for a message in SINGULAR and PLURAL is retrieved based on the argument COUNT. possible placeholders get expanded.
this function is a mixture of xgettext(), ngettext(), and pgettext(), see above! π
[% gtx.ngettext(SINGULAR, PLURAL, COUNT) %]β useless function, provided for completeness. usenxgettext()instead, so that you can interpolate the value of COUNT! π[% gtx.npgettext(CONTEXT, SINGULAR, PLURAL, COUNT) %]β useless function, provided for completeness. usenpxgettext()instead, so that you can interpolate the value of COUNT! π
in fact, you also have all the keywords used for FILTERS available, but the ones not listed here have such an odd ordering of arguments that they just aren't listed here. ngl, fair.
π FILTERS π
the entire gettext API is also exposed as a filter. two things to note here:
- when used as filters, you don't prefix the method names. it's
gettext, notGettext.gettextorgtx.gettext(). - the filters with message contexts have rather strange names, for example:
[% FILTER gettextp("greeting") %]
Hello, world!
[% END %]
or 100 % equivalent:
[% 'Hello, world!' | gettextp("greeting") %]
why? because the text between FILTER and END β or the text in front of the pipe symbol | β is always the first argument. so this plug-in tries to make the first argument the most significant one. nobody's stopping you from writing this:
[% FILTER pgettext("Hello, world!") %]
greeting
[% END %]
or again, 100 % equivalent:
[% 'greeting' | pgettext("Hello, world!") %]
it produces exactly the same results as above, but it looks a little bit odd, doesn't it? π
it would arguably have been better understandable to silently reorder the arguments when using the plug-in as a filter. but that would break extraction of your strings with xgettext-tt2 (Locale::XGettext::TT2), because the string extractor would then confuse the arguments. so, trade-offs.
but stay relaxed! message contexts are rarely needed, and when you do need them, you just have to live with this little weirdness. π
and in order to avoid confusion, those filters that would not have the translatable string (in the singular form) where you'd expect it are not documented here.
you can use the following filters:
[% STRING | gettext %][% FILTER gettext %]STRING[% FILTER %]β retrieves the translation for STRING.[% STRING | xgettext(PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2, ...) %][% FILTER xgettext(PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2, ...) %]STRING[% END %]β gets the translation for a string with placeholders and interpolates values into it. placeholders have the format<{PLACEHOLDER}>. for a literal left curly brace you can use this hack:
[% "String with {LBRACE}PLACEHOLDERS{RBRACE}" | xgettext(LBRACE => "{", RBRACE => "}") %]
[% STRING | gettextp(CONTEXT) %][% FILTER gettextp(CONTEXT) %]STRING[% END %]β retrieves the translation for STRING in context CONTEXT. you should use message context to disambiguate identical strings that require different translations depending on the context. see the documentation forpgettext()in FUNCTIONS above for more details! πΈ[% STRING | xgettextp(CONTEXT, STRING, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %][% FILTER xgettextp(CONTEXT, STRING, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]STRING[% END %]β get the translation for STRING with placeholders in context CONTEXT. this is a mixture ofxgettext()andpgettext()above.[% SINGULAR | nxgettext(PLURAL, COUNT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %][% FILTER nxgettext(PLURAL, COUNT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]SINGULAR[% END %]β retrieves the translation for the string with the singular form SINGULAR and the plural from PLURAL, both possibly containing placeholders. the correct form is picked based upon the third argument COUNT.
example:
[% "One document deleted" | nxgettext("{num} documents deleted"),
count,
num => count) %]
in English this will produce "42 documents deleted" if the variable count has the value 42. it will produce "One document deleted" if the variable count has the value 1.
in other languages, the rules for plural forms may be a lot simpler (for example Chinese, which has no plural) or a lot more complicated (for example Russian with two or Slovenian with even 3 plural forms). using ngettext() gives your translators the chance to provide syntactically correct translations for these cases.
[% SINGULAR | nxgettextp(PLURAL, COUNT, CONTEXT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %][% FILTER nxgettextp(PLURAL, COUNT, CONTEXT, PLACEHOLDER1 => VALUE1, PLACEHOLDER2 => VALUE2) %]SINGULAR[% END %]β putting it all together: for message context CONTEXT the translation for a message in SINGULAR and PLURAL is retrieved based on the argument COUNT. possible placeholders are expanded.
the filter is a mixture of xgettext(), ngettext(), and pgettext(), see above!
[% SINGULAR | ngettext(PLURAL, COUNT) %][% FILTER ngettext(PLURAL, COUNT) %]SINGULAR[% END %]β useless filter, provided for completeness. usenxgettext()instead, so that you can interpolate the value of COUNT! π[% SINGULAR | ngettextp[(PLURAL, COUNT, CONTEXT) %][% FILTER | ngettextp[(PLURAL, COUNT, CONTEXT) %]SINGULAR[% END %]β useless filter, provided for completeness. usenxgettextp()instead, so that you can interpolate the value of COUNT! π[% debug_locale %]β the plug-in implicitly callsweb_set_locale()(see Locale::Util) if a language was specified in the USE statement. the functiondebug_locale()gives you the return value of that call, for debugging purposes. example:
[% USE gtx = Gettext('com.mydomain.www', de') %]
Using locale [% debug_locale() %].
this way, you can figure out whether setting the specified locale actually worked. π¦
π CLASS METHODS π
textdomainsβ returns a hash where the keys are the textdomains found in templates that invoked the plug-in, and the values are the corresponding template file names.
the purpose of this method is to allow harvesting files that should be processed by xgettext-tt2.
if the template is either "input text" or "input file handle", the template variable gettext_filename β if existing β is assumed as the template name. rationale: "input text" and "input file handle" are used by the Template Toolkit as aliases, when reading from a scalar or a file handle.
resetTextdomainsβ resets the hash described above fortextdomain()to its initial, empty state. clean slate energy β¨
π COPYRIGHT π
Copyright (C) 2016-2018 Guido Flohr (http://www.guido-flohr.net/). License LGPLv3+: GNU General Public License version 3 or later <http://gnu.org/licenses/lgpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Copyright (C) 2016-2018 Guido Flohr <guido.flohr@cantanea.com>, all rights reserved.
π SEE ALSO π
- Template
- Template::Manual::Filters
- xgettext-tt2
- perl
and that's a wrap bestie!! π this was perl v5.36.0, dated 2023-07-21, and it lives under Templa...Gettext(3pm) β go forth and translate slayfully, no cap πβ¨π
π¦ where this page comes from
- debian trixie: libtemplate-plugin-gettext-perl 1.0-1 Β· LGPL-3.0-or-later
- ubuntu noble: libtemplate-plugin-gettext-perl 1.0-1 Β· LGPL-3.0-or-later
- ubuntu resolute: libtemplate-plugin-gettext-perl 1.0-1 Β· LGPL-3.0-or-later
- ubuntu stonking: libtemplate-plugin-gettext-perl 1.0-1 Β· LGPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms