1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
|
=encoding utf8
=head1 NAME
Log::Report::Template::Extract - collect translatable strings from template files
=head1 INHERITANCE
Log::Report::Template::Extract
is a Log::Report::Extract
=head1 SYNOPSIS
# Added Log-Report-Template v0.90
# First use of this module: extract msgids from various kinds
# of text-files, usually web templates.
# See script "xgettext-perl" for standard wrapper script
my $extr = Log::Report::Template::Extract->new(
lexicon => '/usr/share/locale',
domain => 'my-web-site',
pattern => 'TT2-loc',
);
$extr->process('website/page.html'); # many times
$extr->showStats;
$extr->write;
# Second use: connect to Template::Toolkit
# See DETAILS chapter below
[% loc("Greetings {name},", name => client.name) %]
[% | loc(name => client.name) %]Greetings {name}[% END %]
[% 'Greetings {name}' | loc(name => client.name) %]
=head1 DESCRIPTION
This module helps maintaining the POT files which list translatable
strings from template files (or other flat text files) by updating the
list of message-ids which are kept in them.
After initiation, the L<process()|Log::Report::Template::Extract/"Processors"> method needs to be called for each file
in the domain and the existing PO files will get updated accordingly.
If no translations exist yet, one C<$textdomain.po> file will be
created as point to start. Copy that file into C<$textdomain/$lang.po>
Extends L<"DESCRIPTION" in Log::Report::Extract|Log::Report::Extract/"DESCRIPTION">.
=head1 METHODS
Extends L<"METHODS" in Log::Report::Extract|Log::Report::Extract/"METHODS">.
=head2 Constructors
Extends L<"Constructors" in Log::Report::Extract|Log::Report::Extract/"Constructors">.
=over 4
=item $class-E<gt>B<new>(%options)
Z<>
-Option --Defined in --Default
charset Log::Report::Extract 'utf-8'
domain <required>
lexicon Log::Report::Extract <required>
pattern <C<undef>>
=over 2
=item charset => STRING
=item domain => DOMAIN
There is no syntax for specifying domains in templates (yet), so you
must be explicit about the collection we are making now.
=item lexicon => DIRECTORY
=item pattern => PREDEFINED|CODE
See the DETAILS section below for a detailed explenation.
=back
=back
=head2 Accessors
Extends L<"Accessors" in Log::Report::Extract|Log::Report::Extract/"Accessors">.
=over 4
=item $obj-E<gt>B<addPot>($domain, $pot, %options)
Inherited, see L<Log::Report::Extract/"Accessors">
=item $obj-E<gt>B<charset>()
Inherited, see L<Log::Report::Extract/"Accessors">
=item $obj-E<gt>B<domain>()
Z<>
=item $obj-E<gt>B<domains>()
Inherited, see L<Log::Report::Extract/"Accessors">
=item $obj-E<gt>B<index>()
Inherited, see L<Log::Report::Extract/"Accessors">
=item $obj-E<gt>B<pattern>()
Z<>
=item $obj-E<gt>B<pots>($domain)
Inherited, see L<Log::Report::Extract/"Accessors">
=back
=head2 Processors
Extends L<"Processors" in Log::Report::Extract|Log::Report::Extract/"Processors">.
=over 4
=item $obj-E<gt>B<cleanup>(%options)
Inherited, see L<Log::Report::Extract/"Processors">
=item $obj-E<gt>B<process>($filename, %options)
Update the domains mentioned in the C<$filename>. All textdomains defined
in the file will get updated automatically, but not written before
all files where processed.
Improves base, see L<Log::Report::Extract/"Processors">
-Option --Default
charset 'utf-8'
pattern <from new(pattern)>
=over 2
=item charset => STRING
The character encoding used in this template file.
=item pattern => PREDEFINED|CODE
Read the DETAILS section about this.
=back
=item $obj-E<gt>B<showStats>( [$domains] )
Inherited, see L<Log::Report::Extract/"Processors">
=item $obj-E<gt>B<store>( $domain, $filename, $linenr, $context, $msg, [$msg_plural] )
Inherited, see L<Log::Report::Extract/"Processors">
=item $obj-E<gt>B<write>( [$domain], %options )
Inherited, see L<Log::Report::Extract/"Processors">
=back
=head1 DETAILS
=head2 Scan Patterns
Various template systems use different conventions for denoting strings
to be translated.
=head3 Predefined for Template-Toolkit
There is not a single convention for translations in C<Template-Toolkit>
(see Template), so you need to specify which version TT you use and
which function name you want to use. In extreme cases, you may even build
separate translation tables by simply providing using functions.
For instance
pattern => 'TT2-loc'
will scan for
[% loc("msgid", key => value, ...) %]
[% loc('msgid', key => value, ...) %]
[% loc("msgid|plural", count, key => value, ...) %]
[% INCLUDE
title = loc('something')
%]
[% | loc(n => name) %]hi {n}[% END %]
[% 'hi {n}' | loc(n => name) %]
For C<TT1>, the brackets can either be '[%...%]' or '%%...%%'. The function
name is treated case-sensitive. Some people prefer 'l()' or 'L()'.
The code needed
# during initiation of the webserver, once in your script (before fork)
my $lexicons = 'some-directory-for-translation-tables';
my $pots = Log::Report::Translator::POT->new(lexicons => $lexicons);
my $templater = Log::Report::Template->new(...);
my $domain = $templater->addTextdomain(
name => $domainname,
function => 'loc',
);
$domain->configure(translator => $pots);
# part of the processing per page
$vars{translate_to} = 'nl_NL.utf8';
$templater->process($template, \%vars, \$output);
To generate the pod tables, run in the shell something like
xgettext-perl -p $lexicons --template TT2-loc \
--domain $textdomain $templates_dir
If you want to implement your own extractor --to avoid C<xgettext-perl>--
you need to run something like this:
my $extr = Log::Report::Template::Extract->new(
lexicon => $output,
charset => 'utf-8',
domain => $domain,
pattern => 'TT2-loc',
);
$extr->process($_) for @filenames;
$extr->write;
=head2 Use in combination with contexts
This example extends the previous with using context sensitive translations,
as implemented by L<Log::Report::Translator::Context|Log::Report::Translator::Context>.
Let's say that the translation of some of the sentences on the website depend
on the gender of the addressed person. An example of the use in a TT2
template:
[% loc("{name<gender} forgot his key", name => person.name) %]
The extraction script F<xgettext-perl> will expand this into two records
in the PO file, respectively with msgctxt attribute 'gender=male' and
'gender=female'.
When your PO-files are not generated by 'xgettext-perl', you do not need
a separate domain configuration file:
$domain->configure(
context_rules => +{gender => ['male','female']},
translator => $translator,
);
When your PO-files are generated by 'xgettext-perl', you need to share
the context-rules between that msgid extractor and your runtime code. That
same file needs to be passed with the 'domain' parameter to the script.
# add context_rules either explicit or via 'config' filename
$domain->configure(
config => 'my/own/$domain.conf',
translator => $translator,
);
Now, when you generate the pages, you need to set-up the right context.
In this case, we set-up the gender of the person who gets addressed.
(The name 'gender' is good for examples, but quite non-descriptive.
Maybe 'user_gender' is more maintainable)
$domain->setContext( +{gender => 'male'} ); # or ('gender=male')
$domain->setContext( "gender=male" ); # same
=head1 DIAGNOSTICS
=over 4
=item Fault: cannot read template from $file: $!
Cast by process()
=item Warning: msgid '$msgid' contains html escapes, don't do that. File $file line $linenr
Cast by process()
=item Error: need pattern to scan for, either via new() or process()
Cast by process()
=item Error: no context tags allowed in plural `$msgid'
Cast by store()
=item Info: processing file $file in $charset
Cast by process()
=item Info: starting new textdomain $domain, template in $filename
Cast by write()
=item Error: template extract requires explicit domain
Cast by new()
=item Error: template syntax error, no END in $fn line $line
Cast by process()
=item Error: unknown pattern $pattern
Cast by process()
=back
=head1 SEE ALSO
This module is part of Log-Report-Template version 1.03,
built on September 08, 2025. Website: F<http://perl.overmeer.net/CPAN/>
=head1 LICENSE
For contributors see file ChangeLog.
This software is copyright (c) 2017-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.
|