Log::R...ontext(3pm)
π Log::Report::Translator::Context π
okay bestie, welcome to Log::Report::Translator::Context β it's the part of the manual that handles translation contexts. it lives in the User Contributed Perl Documentation crew and it is genuinely iconic. it's part 1 of 2, so buckle up, we're not done yet π
β¨ NAME β¨
Log::Report::Translator::Context β handle translation contexts π¦
β¨ SYNOPSIS β¨
# usually, the context information is in a separate file
textdomain 'my-domain',
config => $filename;
β¨ DESCRIPTION β¨
[Added in Log::Report v1.00] so. the "contexts" concept (in GNU's version of gettext) has a very restricted purpose: it's there to separate two accidental uses of the same message-id when they happen under different circumstances. same msgid, translated differently in one file vs the other. that's it, that's the whole job π
for instance, two libraries used inside the same application, or two components inside a single library, both want the same default text (which is usually super short):
char * t1 = pgettext('interface', 'None');
char * t2 = pgettext('selections', 'None');
some translation setups consistently use the library name as the msgctxt. but honestly the name "context" is pretending to have way more power than the gettext libraries can actually deliver β it usually just behaves like a namespace π
for Log::Report tho, the power of "context" gets extended, because now you can select between alternatives for the use of a msgid at the same spot. slay
for instance: the gender of the user of the website decides whether he or she needs to show up in the translation. in this example, the gender is set as a context keyword right in the message:
my ($name, $sex) = ('Jack', 'male');
print __x"{name<gender} found his key", name => $name,
_context => "gender=$sex";
β¨ METHODS β¨
πΈ Constructors
$class->new(%options)
here's the whole option table, no cap:
-Option--Default
rules {}
rules=> HASH β the constructor takes arulesoption, and its default is{}(an empty hash, bestie, nothing in it).
πΈ Attributes
$obj->rules()
returns a HASH pointing at the simplified context maps. that's it. one job, done well. π
πΈ Action
$obj->ctxtFor( $message, $lang, [$context] )
returns a pair: the MSGID stripped of its context markup, and the context evaluated into the msgctxt string. the $message is a Log::Report::Message object. the $context is the default context for a certain textdomain. so it looks like:
my ($msgid, $msgctxt) = $context->ctxtFor($msg, $lang, $context);
$obj->expand($msgid, $language, %options)
expands the context settings into all possible combinations which need translations in the PO file. this may depend on the $language. the $msgid is used in error messages. very thorough of it honestly π
$any->needDecode($source, STRING|ARRAY|HASH|PAIRS)
converts the context settings passed along with the MSGID into a HASH, which then gets matched against the context providers. so it takes a $source that can be a STRING, an ARRAY, a HASH, or PAIRS.
note that this one is called on$any, not on$objβ it's not fussy about who's asking π«Ά
β¨ DETAILS β¨
the "contexts" concept in (GNU's version of) gettext has a very restricted purpose: to separate two (accidental) uses of the same message-id, under different circumstances. the same msgid may be translated differently in one file or the other.
for instance, two libraries used in the same application, or two components within a single library, both want to use the same default text (which usually is very short):
char * t1 = pgettext('interface', 'None');
char * t2 = pgettext('selections', 'None');
some translation setups use the library name consistently as msgctxt. but the name "context" is pretending much more power than the gettext libraries are capable of: it usually only behaves like a namespace.
πΈ Contexts in Log::Report
for Log::Report, the power of "context" is extended with selecting between alternatives for the use of a msgid on the same spot.
for instance, the gender of the user of the website determines whether he or she needs to be used in the translation. in this example, the gender is set as a context keyword in the message:
my ($name, $sex) = ('Jack', 'male');
print __x"{name<gender} found his key", name => $name,
_context => "gender=$sex";
this would also be possible in traditional gettext, although probably rarely used. a complication is that the scripts which maintain the po tables are not too smart β they do not understand complex code constructs. probably you'd need something like this:
if(sex==MALE)
{ printf pgettext('male', "%s found his key\n", name);
}
else
{ printf pgettext('female', "%s found her key\n", name);
}
πΈ Using context_rules
in Log::Report's extended concept of "contexts", you can select between multiple translations for the same msgid, when they:
- appear with different purpose (like gnu's concept of contexts)
- need alternative translation sets on the same spot
- interpolate global parameters in messages
in the standard gettext set-up, some msgid may accidentally collide between two different uses. for instance, whether you translate the word "Open" in the menu for "Files" to mean "open a file", and the word "Open" in the status display meaning "the file is open". in some languages, these translations may differ. using a msgctxt keyword will cause the same msgid to appear twice in the PO-file.
but there's a much broader need for context sensitive translations, which is not provided by standard gettext: environmental information or parameters may influence the translation more than can simply be solved by inserted parameters.
for instance, the gender of the user of the website determines whether he or she needs to be used. in this example, the gender is set as a context keyword in the message:
$name = 'Jack';
print __x"{name} found her key", name => $name;
you may try to solve this via:
my ($name, $gender) = ('Jack', 'male');
print __x"{name} found {personal} key", name => $name,
personal => ($gender eq 'male' ? 'his' : 'her'); # No!
this does NOT translate! π for one, you'd need to translate "his" and "her" to the language as well. but in some languages, the differences between addressed genders have way more impact on the whole sentence.
so, Log::Report translations add extra syntax:
my ($name, $gender) = ('Jack', 'male');
print __x"{name<gender} found her key", name => $name,
_context => "gender=$gender";
the "gender" marking tells the translation table builder (xgettext-perl) and the translation handler that there is a context active. iykyk
now, the English PO-file has:
# gender alternatives 'male' and 'female'
msgctxt "gender=male"
msgid "{name} found his key"
msgstr "{name} found his key"
msgctxt "gender=female"
msgid "{name} found his key"
msgstr "{name} found her key"
to make this work, both the application and the xgettext-perl script must share information to understand which genders are available. see the section on "Configuration" below. π
another example:
print __x"greetings{<style}";
# style alternatives 'formal' and 'informal'
msgctxt "style=formal"
msgid "greetings"
msgstr "Dear Sir/Madam,"
msgctxt "style=informal"
msgid "greetings"
msgstr "Hey buddy,"
as you can see, the <style marking may be added inside the {} of a filled-in parameter, or it may appear on its own. these markings are removed from the msgid in the PO file, so you may freely add them to the strings used in your program without disturbing existing translations. (yes, freedom π
)
π« Specifying the context per Message
you need to specify the context at each message which is influenced by the context. this can be a comma separated list of words, an ARRAY, or a HASH:
_context => 'gender=male'
_context => 'gender=male,agegroup=adult,married=yes'
_context => [ 'gender=male', 'agegroup=adult', 'married=yes']
_context => [ qw/gender=male agegroup=adult married=yes/ ]
my @context = (qw/gender=male agegroup=adult married=yes/);
_context => \@context;
probably the
my %context = (gender => 'male', agegroup => 'adult', married => 'yes');
my %context = qw/gender male agegroup adult married yes/;
_context => \%context;
standard gettext only allows a single keyword (=string). "Log::Report" permits you to set-up a context for a whole text-domain, which means that multiple context rules may be active at any moment. π¦
π« Global parameters
you can use contexts to set global interpolation parameters. for instance, running a pure perl webserver, you may serve multiple domains. some of the log messages may need to show that domain name. of course, you can collect (or pass on) the hostname when throwing the error... something like this:
# can I access $vhost easily?
error __x"For {host}, login failed for {user}",
host => $vhost->name, user => $user;
via contexts:
# when you know the vhost: (max once per request)
textdomain->setContext(host => $vhost->name); # or updateContext
# until you reconfigure the context
error __x"For {_context.host}, login failed for {user}", user => $user;
the context values are always available for interpolation. π
π« Specifying the context per Domain
the examples above are specified per message. you may also set a default. the top of your modules sets the text-domain (name of the translation table) for all strings found in those files. in this case, for instance "webpages":
# Log::Report::textdomain()
(textdomain 'webpages')->setContext(%context);
this context is used as defaults, and the _context attribute used by strings overrules these. π
π« The msgctxt
the gnutext implementation of the context is very simple. this is to be expected from a library written in C. π₯² the msgctxt alternatives are matched against the context keywords of the message. if all of the alternatives match, or none of them match β then just a random translation is chosen.
in the simplest form, the msgctxt field contains a single keyword (not containing a comma):
msgctxt "gender=male"
but you can do more. be warned that most (all?) existing tools which smartly edit PO-files do not understand these constructs: they see the msgctxt as a dump string without meaning.
msgctxt "agegroup=baby,agegroup=grandparent" # baby OR grandparent
msgctxt "gender=male agegroup=adult" # both male AND adult
so: a comma separated list of alternatives. if any matches, then the rule is selected. β¨
π« Configuration
the tools which handle translations expect the msgctxt to be static. for instance, containing a filename where the string is used, to disambiguate accidental collisions of the use of the same msgid for different purposes.
now, we have designed far more flexible contexts. we need to generate all possible msgctxt values while extracting msgids to update the PO-files. therefore, we need a map-file. πΊοΈ
the context maps are included in a configuration file which is passed to xgettext-perl and to the program which uses contexts. see Log::Report::Domain::readConfig().
example of such configuration file: (JSON syntax and Perl syntax)
Okay so boom β here's how the same config looks in JSON versus Perl, side by side, bestie:
=== JSON === ==== Perl == =
{{
"context_rules" : { context_rules => {
"gender" : [ gender => [
"male", 'male',
"female" 'female'
] ]
} }
} }
fr fr either vibes:
{ {
"context_rules" : { context_rules => {
"gender" : { gender => {
"alternatives" : [ alternatives => [
"male", 'male',
"female", 'female',
"unknown" 'unknown'
] ]
... more config for 'gender' ...
} }
} }
} }
So as alternatives, we list the alternatives exactly as the application internals know them. Every msgid that has a {<gender} mark inside it gets replicated three times, in each language table. And every copy gets marked with a different value from alternatives. π
But here's the thing β languages are different, okay? Like, in some language you might address the "unknown" gender as if it were a male person. In other languages, the translation can actually express that "unknown" personality. To make that work, you get to use the msgctxt construct. π
The default msgctxt, like in the example before, just maps the alternatives straight onto msgctxt values that are identical to them:
{ { context_rules =>
"context_rules" : { { gender =>
"gender" : { { default => { qw/
"default" : { female female
"female" : "female", male male
"male" : "male" unknown male / }
"unknown" : "male", , 'nl,de' => { qw/
}, unknown x / }
"nl,de" : {
"unknown" : "x"
} }
... more configuration ...
}
... more context rules ...
} }
} }
By default, you'll only get two msgid copies in a language file, because at run-time the unknown is mapped onto male. The exception β¨ is the Dutch (nl*) and German (de*) tables, which apparently support that third gender.
And if you're just not interested in a certain tag? Put it on IGNORE β either as default or for your specific language:
"default" : "IGNORE", default => 'IGNORE'
"nl": "IGNORE" nl => 'IGNORE'
π©Ί DIAGNOSTICS π©Ί
Bestie, here's your vibe-check decoder ring for when things go sideways:
Error: no context definition for$tag' in$msgid'β cast byctxtFor()- **
Warning: no value for tag$tag' in the context**</yellow> β cast byctxtFor()` - **
Error: tags value must have forma=b', found$this' in$source'**</red> β cast byneedDecode()` - **
Warning: unknown alternative$alt' for tag$tag' in context of$msgid'**</yellow> β cast byctxtFor()` Error: unknown context tag '$tag' used in '$msgid'β cast byexpand()
π SEE ALSO π
This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: http://perl.overmeer.net/CPAN/ π
π LICENSE π
For contributors, see file ChangeLog.
This software is copyright (c) 2007-2025 by Mark Overmeer.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. π«Ά
And that's a wrap, queen π β docs generated from perl v5.40.1, dated 2025-11-11, serving you that Log::R...ontext(3pm) realness. Go forth and localize responsibly, no cap. πβ¨π
π¦ where this page comes from
- ubuntu resolute: liblog-report-lexicon-perl 1.15-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: liblog-report-lexicon-perl 1.15-1 Β· 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