Log::Report::Template::Extract(3pm)

NAME
Log::Report::Template::Extract - collect translatable strings from template files

INHERITANCE
 Log::Report::Template::Extract
   is a Log::Report::Extract

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) %]

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 process() 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 "$textdomain.po" file will be created as point to start. Copy that file into "$textdomain/$lang.po"

Extends "DESCRIPTION" in Log::Report::Extract.

METHODS
Extends "METHODS" in Log::Report::Extract.

  Constructors
Extends "Constructors" in Log::Report::Extract.

$class->new(%options)

     -Option --Defined in          --Default
      charset  Log::Report::Extract  'utf-8'
      domain                         <required>
      lexicon  Log::Report::Extract  <required>
      pattern                        <C<undef>>

    charset => STRING
    domain => DOMAIN
        There is no syntax for specifying domains in templates (yet), so you must be explicit about the collection we are making now.

    lexicon => DIRECTORY
    pattern => PREDEFINED|CODE
        See the DETAILS section below for a detailed explenation.

  Accessors
Extends "Accessors" in Log::Report::Extract.

$obj->addPot($domain, $pot, %options)
    Inherited, see "Accessors" in Log::Report::Extract

$obj->charset()
    Inherited, see "Accessors" in Log::Report::Extract

$obj->domain()

$obj->domains()
    Inherited, see "Accessors" in Log::Report::Extract

$obj->index()
    Inherited, see "Accessors" in Log::Report::Extract

$obj->pattern()

$obj->pots($domain)
    Inherited, see "Accessors" in Log::Report::Extract

  Processors
Extends "Processors" in Log::Report::Extract.

$obj->cleanup(%options)
    Inherited, see "Processors" in Log::Report::Extract

$obj->process($filename, %options)
    Update the domains mentioned in the $filename. All textdomains defined in the file will get updated automatically, but not written before all files where processed. Improves base, see "Processors" in Log::Report::Extract

     -Option --Default
      charset  'utf-8'
      pattern  <from new(pattern)>

    charset => STRING
        The character encoding used in this template file.

    pattern => PREDEFINED|CODE
        Read the DETAILS section about this.

$obj->showStats( [$domains] )
    Inherited, see "Processors" in Log::Report::Extract

$obj->store( $domain, $filename, $linenr, $context, $msg, [$msg_plural] )
    Inherited, see "Processors" in Log::Report::Extract

$obj->write( [$domain], %options )
    Inherited, see "Processors" in Log::Report::Extract

DETAILS

  Scan Patterns
Various template systems use different conventions for denoting strings to be translated.

Predefined for Template-Toolkit

There is not a single convention for translations in "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 "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 "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;

  Use in combination with contexts
This example extends the previous with using context sensitive translations, as implemented by 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 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

DIAGNOSTICS

Fault: cannot read template from $file: $!
    Cast by process()

Warning: msgid '$msgid' contains html escapes, don't do that.  File $file line $linenr
    Cast by process()

Error: need pattern to scan for, either via new() or process()
    Cast by process()

Error: no context tags allowed in plural `$msgid'
    Cast by store()

Info: processing file $file in $charset
    Cast by process()

Info: starting new textdomain $domain, template in $filename
    Cast by write()

Error: template extract requires explicit domain
    Cast by new()

Error: template syntax error, no END in $fn line $line
    Cast by process()

Error: unknown pattern $pattern
    Cast by process()

SEE ALSO
This module is part of Log-Report-Template version 1.04, built on November 04, 2025. Website: http://perl.overmeer.net/CPAN/

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.