Log-Report-Lexicon-1.15/0000755000175000001440000000000015103071407015545 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/0000755000175000001440000000000015103071406016312 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/0000755000175000001440000000000015103071406017033 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/0000755000175000001440000000000015103071406020306 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/Extract/0000755000175000001440000000000015103071406021720 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/Extract/PerlPPI.pod0000644000175000001440000001362415103071404023703 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Extract::PerlPPI - Collect translatable strings from Perl using PPI =head1 INHERITANCE Log::Report::Extract::PerlPPI is a Log::Report::Extract =head1 SYNOPSIS my $ppi = Log::Report::Extract::PerlPPI->new( lexicon => '/usr/share/locale', ); $ppi->process('lib/My/Pkg.pm'); # call for each .pm file $ppi->showStats; # optional $ppi->write; # See script xgettext-perl bin/xgettext-perl -p $lexdir @source_dirs =head1 DESCRIPTION This module helps maintaining the POT files, updating the list of message-ids which are kept in them. After initiation, the L method needs to be called with all files which changed since last processing and the existing PO files will get updated accordingly. If no translations exist yet, one C<$lexicon/$domain.po> file will be created. If you want to start a translation, copy C<$lexicon/$domain.po> to C<$lexicon/$domain/$lang.po> and edit that file. You may use C to edit po-files. There are many smart translation management applications which can hand po-files, for instance Pootle and Weblate. Do not forget to add the new po-file to your distribution (MANIFEST) Extends L<"DESCRIPTION" in Log::Report::Extract|Log::Report::Extract/"DESCRIPTION">. =head2 The extraction process All pm-files need to be processed in one go: no incremental processing! The Perl source is parsed using PPI, which does understand Perl syntax quite well, but does not support all features. Automatically, the textdomain of the translations is discovered, as first parameter of C. You may switch textdomain inside one pm-file. When all files have been processed, during the L, all existing po-files for all discovered textdomains will get updated. Not only the C<$lexicon/$domain.po> template, but also all C<$lexicon/$domain/$lang.po> will be replaced. When a msgid has disappeared, existing translations will get disabled, not removed. New msgids will be added and flagged "fuzzy". =head3 What is extracted? This script will extract the msgids used in C<__()>, C<__x()>, C<__xn()>, and C<__n()> (implemented by L) For instance __x"msgid", @more __x'msgid', @more <--- no! syntax error! __x("msgid", @more) __x('msgid', @more) __x(msgid => @more) Besides, there are some helpers which are no-ops in the code, only to fill the po-tables: C, C, C =head3 What is not extracted? B extracted are the usage of anything above, where the first parameter is not a simple string. Not extracted are __x($format, @more) __x$format, @more __x(+$format, _domain => 'other domain', @more) __x($first.$second, @more) In these cases, you have to use C functions to declare the possible values of C<$format>. =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-EB(%options) Inherited, see L =back =head2 Accessors Extends L<"Accessors" in Log::Report::Extract|Log::Report::Extract/"Accessors">. =over 4 =item $obj-EB($domain, $pot, %options) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB($domain) Inherited, see L =back =head2 Processors Extends L<"Processors" in Log::Report::Extract|Log::Report::Extract/"Processors">. =over 4 =item $obj-EB(%options) Inherited, see L =item $obj-EB($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 -Option --Default charset 'iso-8859-1' =over 2 =item charset => $charset PPI v1.284 still does not support unicode by itself, so you need to help it by specifying the character-set which is used in the file. =back =item $obj-EB( [$domains] ) Inherited, see L =item $obj-EB( $domain, $filename, $linenr, $context, $msg, [$msg_plural] ) Inherited, see L =item $obj-EB( [$domain], %options ) Inherited, see L =back =head1 DIAGNOSTICS =over 4 =item Fault: cannot create lexicon directory $dir: $! Cast by C =item Fault: cannot read perl from file $filename: $! Cast by C =item Error: count missing in $function in line $line Cast by C =item Error: extractions require an explicit lexicon directory Cast by C =item Info: no Perl in file $filename Cast by C =item Error: no context tags allowed in plural `$msgid' Cast by C =item Info: processing file $fn in $charset Cast by C =item Info: starting new textdomain $domain, template in $filename Cast by C =item Error: string is incorrect at line $line: $error Cast by C =item Warning: use double quotes not single, in $string on $file line $line Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Extract/Template.pm0000644000175000001440000001135415000465534024042 0ustar00markovusers00000000000000# Copyrights 2007-2025 by [Mark Overmeer ]. # For other contributors see ChangeLog. # See the manual pages for details on the licensing terms. # Pod stripped from pm file by OODoc 2.03. # This code is part of distribution Log-Report-Lexicon. Meta-POD processed # with OODoc into POD and HTML manual-pages. See README.md # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. package Log::Report::Extract::Template;{ our $VERSION = '1.12'; } use base 'Log::Report::Extract'; use warnings; use strict; use Log::Report 'log-report-lexicon'; sub init($) { my ($self, $args) = @_; $self->SUPER::init($args); $self->{LRET_domain} = $args->{domain} or error "template extract requires explicit domain"; $self->{LRET_pattern} = $args->{pattern}; $self; } #---------- sub domain() {shift->{LRET_domain}} sub pattern() {shift->{LRET_pattern}} #---------- sub process($@) { my ($self, $fn, %opts) = @_; my $charset = $opts{charset} || 'utf-8'; info __x"processing file {fn} in {charset}", fn=> $fn, charset => $charset; my $pattern = $opts{pattern} || $self->pattern or error __"need pattern to scan for, either via new() or process()"; # Slurp the whole file local *IN; open IN, "<:encoding($charset)", $fn or fault __x"cannot read template from {fn}", fn => $fn; undef $/; my $text = ; close IN; my $domain = $self->domain; $self->_reset($domain, $fn); if(ref $pattern eq 'CODE') { return $pattern->($fn, \$text); } elsif($pattern =~ m/^TT([12])-(\w+)$/) { return $self->scanTemplateToolkit($1, $2, $fn, \$text); } else { error __x"unknown pattern {pattern}", pattern => $pattern; } (); } sub _no_escapes_in($$$$) { my ($msgid, $plural, $fn, $linenr) = @_; return if $msgid !~ /\&\w+\;/ && (defined $plural ? $plural !~ /\&\w+\;/ : 1); $msgid .= "|$plural" if defined $plural; warning __x"msgid '{msgid}' contains html escapes, don't do that. File {fn} line {linenr}" , msgid => $msgid, fn => $fn, linenr => $linenr; } sub scanTemplateToolkit($$$$) { my ($self, $version, $function, $fn, $textref) = @_; # Split the whole file on the pattern in four fragments per match: # (text, leading, needed trailing, text, leading, ...) # f.i. ('', '[% loc("', 'some-msgid', '", params) %]', ' more text') my @frags = $version==1 ? split(/[\[%]%(.*?)%[%\]]/s, $$textref) : split(/\[%(.*?)%\]/s, $$textref); my $domain = $self->domain; my $linenr = 1; my $msgs_found = 0; # pre-compile the regexes, for performance my $pipe_func_block = qr/^\s*(?:\|\s*|FILTER\s+)$function\b/; my $msgid_pipe_func = qr/^\s*(["'])([^\r\n]+?)\1\s*\|\s*$function\b/; my $func_msgid_multi = qr/(\b$function\s*\(\s*)(["'])([^\r\n]+?)\2/s; while(@frags > 2) { my ($skip_text, $take) = (shift @frags, shift @frags); $linenr += $skip_text =~ tr/\n//; if($take =~ $pipe_func_block) { # [% | loc(...) %] $msgid [%END%] or [% FILTER ... %]...[% END %] if(@frags < 2 || $frags[1] !~ /^\s*END\s*$/) { error __x"template syntax error, no END in {fn} line {line}" , fn => $fn, line => $linenr; } my $msgid = $frags[0]; # next content my $plural = $msgid =~ s/\|(.*)// ? $1 : undef; _no_escapes_in $msgid, $plural, $fn, $linenr; $self->store($domain, $fn, $linenr, $msgid, $plural); $msgs_found++; $linenr += $take =~ tr/\n//; next; } if($take =~ $msgid_pipe_func) { # [% $msgid | loc(...) %] my $msgid = $2; my $plural = $msgid =~ s/\|(.*)// ? $1 : undef; _no_escapes_in $msgid, $plural, $fn, $linenr; $self->store($domain, $fn, $linenr, $msgid, $plural); $msgs_found++; $linenr += $take =~ tr/\n//; next; } # loc($msgid, ...) form, can appear more than once my @markup = split $func_msgid_multi, $take; while(@markup > 4) { # quads with text, call, quote, msgid $linenr += ($markup[0] =~ tr/\n//) + ($markup[1] =~ tr/\n//); my $msgid = $markup[3]; my $plural = $msgid =~ s/\|(.*)// ? $1 : undef; _no_escapes_in $msgid, $plural, $fn, $linenr; $self->store($domain, $fn, $linenr, $msgid, $plural); $msgs_found++; splice @markup, 0, 4; } $linenr += $markup[-1] =~ tr/\n//; # rest of container } # $linenr += $frags[-1] =~ tr/\n//; # final page fragment not needed $msgs_found; } #---------------------------------------------------- 1; Log-Report-Lexicon-1.15/lib/Log/Report/Extract/Template.pod0000644000175000001440000002000115000465535024176 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Extract::Template - collect translatable strings from template files =head1 INHERITANCE Log::Report::Extract::Template is a Log::Report::Extract =head1 SYNOPSIS # 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::Extract::Template->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 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 Log::Report::Extract::Template-EB(%options) -Option --Defined in --Default charset Log::Report::Extract 'utf-8' domain lexicon Log::Report::Extract pattern =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-EB($domain, $pot, %options) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB() =item $obj-EB() Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB() =item $obj-EB($domain) Inherited, see L =back =head2 Processors Extends L<"Processors" in Log::Report::Extract|Log::Report::Extract/"Processors">. =over 4 =item $obj-EB(%options) Inherited, see L =item $obj-EB($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. -Option --Default charset 'utf-8' 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-EB( [$domains] ) Inherited, see L =item $obj-EB( $domain, $filename, $linenr, $context, $msg, [$msg_plural] ) Inherited, see L =item $obj-EB( [$domain] ) Inherited, see L =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 (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 $translator = Log::Report::Translator::POT->new(lexicons => $lexicons); my $domain = textdomain $textdomain; $domain->configure(translator => $translator); # your standard template driver sub handler { ... my $vars = { ...all kinds of values... }; $vars->{loc} = \&translate; # <--- this is extra my $output = ''; my $templater = Template->new(...); $templater->process($template_fn, $vars, \$output); print $output; } # anywhere in the same file sub translate { my $textdomain = ...; # your choice when running xgettext-perl my $lang = ...; # how do you figure that out? my $msg = Log::Report::Message->fromTemplateToolkit($textdomain, @_); $msg->toString($lang); } 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-- you need to run something like this: my $extr = Log::Report::Extract::Template->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. 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 person.name) %] The extraction script F 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 SEE ALSO This module is part of Log-Report-Lexicon distribution version 1.12, built on April 18, 2025. Website: F =head1 LICENSE Copyrights 2007-2025 by [Mark Overmeer ]. For other contributors see ChangeLog. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F Log-Report-Lexicon-1.15/lib/Log/Report/Extract/PerlPPI.pm0000644000175000001440000001362515103071404023536 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Extract::PerlPPI;{ our $VERSION = '1.15'; } use base 'Log::Report::Extract'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use PPI (); use Encode qw/decode/; # See Log::Report translation markup functions my %msgids = ( # MSGIDs COUNT OPTS VARS SPLIT __ => [1, 0, 0, 0, 0], __x => [1, 0, 1, 1, 0], __xn => [2, 1, 1, 1, 0], __nx => [2, 1, 1, 1, 0], __n => [2, 1, 1, 0, 0], N__ => [1, 0, 1, 1, 0], # may be used with opts/vars N__n => [2, 0, 1, 1, 0], # idem N__w => [1, 0, 0, 0, 1], ); my $quote_mistake; { my @q = map quotemeta, keys %msgids; local $" = '|'; $quote_mistake = qr/^(?:@q)\'/; } #-------------------- sub process($@) { my ($self, $fn, %opts) = @_; my $charset = $opts{charset} || 'iso-8859-1'; my $doc = PPI::Document->new($fn, readonly => 1) or fault __x"cannot read perl from file {filename}", filename => $fn; my @childs = $doc->schildren; if(@childs==1 && ref $childs[0] eq 'PPI::Statement') { info __x"no Perl in file {filename}", filename => $fn; return 0; } info __x"processing file {fn} in {charset}", fn=> $fn, charset => $charset; my ($pkg, $include, $domain, $msgs_found) = ('main', 0, undef, 0); NODE: foreach my $node ($doc->schildren) { if($node->isa('PPI::Statement::Package')) { $pkg = $node->namespace; # special hack needed for module Log::Report itself if($pkg eq 'Log::Report') { ($include, $domain) = (1, 'log-report'); $self->_reset($domain, $fn); } else { ($include, $domain) = (0, undef) } next NODE; } # Take domains which are as first parameter after 'use Log::Report' if($node->isa('PPI::Statement::Include') && $node->type eq 'use') { my $module = $node->module or next NODE; if($module eq 'utf8') { $charset = 'utf-8'; } elsif($module eq 'Log::Report' || $module eq 'Dancer2::Plugin::LogReport') { $include++; if(my $dom = ($node->arguments)[0]) { $domain = $dom->isa('PPI::Token::Quote') ? $dom->string : $dom->isa('PPI::Token::QuoteLike::Words') ? ($dom->literal)[0] : undef; } $self->_reset($domain, $fn) if defined $domain; } next NODE; } $node->find_any( sub { # look for the special translation markers $_[1]->isa('PPI::Token::Word') or return 0; my $node = $_[1]; my $word = $node->content; if($word =~ $quote_mistake) { warning __x"use double quotes not single, in {string} on {file} line {line}", string => $word, fn => $fn, line => $node->location->[0]; return 0; } my $def = $msgids{$word} # get __() description or return 0; # Avoid the declaration of the conversion routines in Log::Report $domain ne 'log-report' || ! $node->parent->isa('PPI::Statement::Sub') or return 0; my @raw_msgids = $self->_get($node, $domain, $word, $def) or return 0; # PPI does not understand utf-8 :-( my @msgids = map decode($charset, $_), @raw_msgids; my ($nr_msgids, $has_count, $has_opts, $has_vars, $do_split) = @$def; my $line = $node->location->[0]; unless($domain) { mistake __x"no text-domain for translatable at {fn} line {line}", fn => $fn, line => $line; return 0; } my @records = $do_split ? (map +[$_], map { split } @msgids) # Bulk conversion strings : \@msgids; $msgs_found += @records; $self->store($domain, $fn, $line, @$_) for @records; 0; # don't collect }); } $msgs_found; } sub _get($$$$) { my ($self, $node, $domain, $function, $def) = @_; my ($nr_msgids, $has_count, $opts, $vars, $split) = @$def; my $list_only = ($nr_msgids > 1) || $has_count || $opts || $vars; my $expand = $opts || $vars; my @msgids; my $first = $node->snext_sibling; $first = $first->schild(0) if $first->isa('PPI::Structure::List'); $first = $first->schild(0) if $first->isa('PPI::Statement::Expression'); my $line; while(defined $first && $nr_msgids > @msgids) { my $msgid; my $next = $first->snext_sibling; my $sep = $next && $next->isa('PPI::Token::Operator') ? $next : ''; $line = $first->location->[0]; if($first->isa('PPI::Token::Quote')) { last if $sep !~ m/^ (?: | \=\> | [,;:] ) $/x; $msgid = $first->string; if( $first->isa("PPI::Token::Quote::Double") || $first->isa("PPI::Token::Quote::Interpolate")) { $first->string !~ m/(? $1, line => $line; # content string is uninterpreted, warnings to screen $msgid = eval "qq{$msgid}"; error __x "string is incorrect at line {line}: {error}", line => $line, error => $@ if $@; } } elsif($first->isa('PPI::Token::Word')) { last if $sep ne '=>'; $msgid = $first->content; } else { last } $split || $msgid !~ s/(? $line; push @msgids, $msgid; last if $nr_msgids==@msgids || !$sep; $first = $sep->snext_sibling; } @msgids or return (); my $next = $first->snext_sibling; !$has_count || $next or error __x"count missing in {function} in line {line}", function => $function, line => $line; @msgids; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/0000755000175000001440000000000015103071406021707 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/POT.pm0000644000175000001440000001722315103071403022711 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! #oorestyle: old style disclaimer to be removed. #oorestyle: not found P for method filename($filename) # This code is part of distribution Log-Report-Lexicon. Meta-POD processed # with OODoc into POD and HTML manual-pages. See README.md # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. package Log::Report::Lexicon::POT;{ our $VERSION = '1.15'; } use base 'Log::Report::Lexicon::Table'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use Log::Report::Lexicon::PO (); use POSIX qw/strftime/; use List::Util qw/sum/; use Scalar::Util qw/blessed/; use Encode qw/decode/; use constant MSGID_HEADER => ''; #-------------------- sub init($) { my ($self, $args) = @_; $self->{LRLP_fn} = $args->{filename}; $self->{LRLP_index} = $args->{index} || {}; $self->{LRLP_charset} = $args->{charset} || 'UTF-8'; my $version = $args->{version}; my $domain = $args->{textdomain} or error __"textdomain parameter is required"; my $forms = $args->{plural_forms}; unless($forms) { my $nrplurals = $args->{nr_plurals} || 2; my $algo = $args->{plural_alg} || 'n!=1'; $forms = "nplurals=$nrplurals; plural=($algo);"; } $self->_createHeader( project => $domain . (defined $version ? " $version" : ''), forms => $forms, charset => $args->{charset}, date => $args->{date} ); $self->setupPluralAlgorithm; $self; } sub read($@) { my ($class, $fn, %args) = @_; my $self = bless {LRLP_index => {}}, $class; my $charset = $args{charset}; $charset = $1 if !$charset && $fn =~ m!\.([\w-]+)(?:\@[^/\\]+)?\.po$!i; my $fh; if(defined $charset) { open $fh, "<:encoding($charset):crlf", $fn or fault __x"cannot read in {cs} from file {fn}", cs => $charset, fn => $fn; } else { open $fh, '<:raw:crlf', $fn or fault __x"cannot read from file {fn} (unknown charset)", fn=>$fn; } local $/ = "\n\n"; my $linenr = 1; # $/ frustrates $fh->input_line_number while(1) { my $location = "$fn line $linenr"; my $block = <$fh>; defined $block or last; $linenr += $block =~ tr/\n//; $block =~ s/\s+\z//s; length $block or last; unless($charset) { $charset = $block =~ m/\"content-type:.*?charset=["']?([\w-]+)/mi ? $1 : error __x"cannot detect charset in {fn}", fn => $fn; trace "auto-detected charset $charset for $fn"; binmode $fh, ":encoding($charset):crlf"; $block = decode $charset, $block or error __x"unsupported charset {charset} in {fn}", charset => $charset, fn => $fn; } my $po = Log::Report::Lexicon::PO->fromText($block, $location); $self->add($po) if $po; } close $fh or fault __x"failed reading from file {fn}", fn => $fn; $self->{LRLP_fn} = $fn; $self->{LRLP_charset} = $charset; $self->setupPluralAlgorithm; $self; } sub write($@) { my $self = shift; my $file = @_%2 ? shift : $self->filename; my %args = @_; defined $file or error __"no filename or file-handle specified for PO"; my $need_refs = $args{only_active}; my @opt = (nr_plurals => $self->nrPlurals); my $fh; if(ref $file) { $fh = $file } else { my $layers = '>:encoding('.$self->charset.')'; open $fh, $layers, $file or fault __x"cannot write to file {fn} with {layers}", fn => $file, layers => $layers; } $fh->print($self->msgid(MSGID_HEADER)->toString(@opt)); my $index = $self->index; foreach my $msgid (sort keys %$index) { next if $msgid eq MSGID_HEADER; my $rec = $index->{$msgid}; my @recs = blessed $rec ? $rec # one record with $msgid : @{$rec}{sort keys %$rec}; # multiple records, msgctxt foreach my $po (@recs) { next if $po->useless; next if $need_refs && !$po->references; $fh->print("\n", $po->toString(@opt)); } } $fh->close or failure __x"write errors for file {fn}", fn => $file; $self; } #-------------------- sub charset() { $_[0]->{LRLP_charset} } sub index() { $_[0]->{LRLP_index} } sub filename() { $_[0]->{LRLP_fn} } sub language() { $_[0]->filename =~ m![/\\](\w+)[^/\\]*$! ? $1 : undef } #-------------------- sub msgid($;$) { my ($self, $msgid, $msgctxt) = @_; my $msgs = $self->index->{$msgid} or return; return $msgs if blessed $msgs && (!$msgctxt || $msgctxt eq $msgs->msgctxt); $msgs->{$msgctxt}; } sub msgstr($;$$) { my ($self, $msgid, $count, $msgctxt) = @_; my $po = $self->msgid($msgid, $msgctxt) or return undef; $count //= 1; $po->msgstr($self->pluralIndex($count)); } sub add($) { my ($self, $po) = @_; my $msgid = $po->msgid; my $index = $self->index; my $h = $index->{$msgid}; $h or return $index->{$msgid} = $po; $h = $index->{$msgid} = +{ ($h->msgctxt // '') => $h } if blessed $h; my $ctxt = $po->msgctxt // ''; error __x"translation already exists for '{msgid}' with '{ctxt}", msgid => $msgid, ctxt => $ctxt if $h->{$ctxt}; $h->{$ctxt} = $po; } sub translations(;$) { my $self = shift; @_ or return map +(blessed $_ ? $_ : values %$_), values %{$self->index}; error __x"the only acceptable parameter is 'ACTIVE', not '{p}'", p => $_[0] if $_[0] ne 'ACTIVE'; grep $_->isActive, $self->translations; } sub _now() { strftime "%Y-%m-%d %H:%M%z", localtime } sub header($;$) { my ($self, $field) = (shift, shift); my $header = $self->msgid(MSGID_HEADER) or error __x"no header defined in POT for file {fn}", fn => $self->filename; if(!@_) { my $text = $header->msgstr(0) || ''; return $text =~ m/^\Q$field\E\:\s*([^\n]*?)\;?\s*$/im ? $1 : undef; } my $content = shift; my $text = $header->msgstr(0); for($text) { if(defined $content) { s/^\Q$field\E\:([^\n]*)/$field: $content/im # change || s/\z/$field: $content\n/; # new } else { s/^\Q$field\E\:[^\n]*\n?//im; # remove } } $header->msgstr(0, $text); $content; } sub updated(;$) { my $self = shift; my $date = shift || _now; $self->header('PO-Revision-Date', $date); $date; } ### internal sub _createHeader(%) { my ($self, %args) = @_; my $date = $args{date} || _now; my $header = Log::Report::Lexicon::PO->new(msgid => MSGID_HEADER, msgstr => <<__CONFIG); Project-Id-Version: $args{project} Report-Msgid-Bugs-To: POT-Creation-Date: $date PO-Revision-Date: $date Last-Translator: Language-Team: MIME-Version: 1.0 Content-Type: text/plain; charset=$args{charset} Content-Transfer-Encoding: 8bit Plural-Forms: $args{forms} __CONFIG my $version = $Log::Report::VERSION || '0.0'; $header->addAutomatic("Header generated with ".__PACKAGE__." $version\n"); $self->index->{&MSGID_HEADER} = $header if $header; $header; } sub removeReferencesTo($) { my ($self, $filename) = @_; sum map $_->removeReferencesTo($filename), $self->translations; } sub keepReferencesTo($) { my ($self, $keep) = @_; sum map $_->keepReferencesTo($keep), $self->translations; } sub stats() { my $self = shift; my %stats = (msgids => 0, fuzzy => 0, inactive => 0); foreach my $po ($self->translations) { next if $po->msgid eq MSGID_HEADER; $stats{msgids}++; $stats{fuzzy}++ if $po->fuzzy; $stats{inactive}++ if !$po->isActive && !$po->useless; } \%stats; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/Table.pm0000644000175000001440000000371715103071404023302 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Lexicon::Table;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; #-------------------- sub new(@) { my $class = shift; (bless {}, $class)->init({@_}) } sub init($) { $_[0] } #-------------------- #-------------------- sub msgid($;$) {panic "not implemented"} sub msgstr($;$$) {panic "not implemented"} #-------------------- sub add($) {panic "not implemented"} sub translations(;$) {panic "not implemented"} sub pluralIndex($) { my ($self, $count) = @_; my $algo = $self->{algo} or error __x"there is no Plural-Forms field in the header, but needed"; $algo->($count); } sub setupPluralAlgorithm() { my $self = shift; my $forms = $self->header('Plural-Forms') or return; my $alg = $forms =~ m/plural\=([n%!=><\s\d|&?:()]+)/ ? $1 : "n!=1"; $alg =~ s/\bn\b/(\$_[0])/g; my $code = eval "sub(\$) {$alg}"; $@ and error __x"invalid plural-form algorithm '{alg}'", alg => $alg; $self->{algo} = $code; $self->{nplurals} = $forms =~ m/\bnplurals\=(\d+)/ ? $1 : 2; $self; } sub nrPlurals() { $_[0]->{nplurals} } sub header($@) { my ($self, $field) = @_; my $header = $self->msgid('') or return; $header =~ m/^\Q$field\E\:\s*([^\n]*?)\;?\s*$/im ? $1 : undef; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/MOTcompact.pod0000644000175000001440000001312515103071404024421 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::MOTcompact - use translations from an MO file =head1 INHERITANCE Log::Report::Lexicon::MOTcompact is a Log::Report::Lexicon::Table =head1 SYNOPSIS # using a MO table efficiently my $mot = Log::Report::Lexicon::MOTcompact->read('mo/nl.mo') or die; my $header = $mot->msgid(''); print $mot->msgstr($msgid, 3); =head1 DESCRIPTION This module is translating, based on MO files (binary versions of the PO files, the "Machine Object" format) Actually, this module is not "compact" anymore: not trading off speed for memory. That may change again in the future. To get a MO file, you first need a PO file. Then run F, which is part of the gnu gettext package. msgfmt -cv -o $domain.mo $domain.po # -c = --check-format & --check-header & --check-domain # -v = --verbose # -o = --output-file Extends L<"DESCRIPTION" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"DESCRIPTION">. =head1 METHODS Extends L<"METHODS" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"METHODS">. =head2 Constructors Extends L<"Constructors" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Constructors">. =over 4 =item $class-EB(%options) Inherited, see L =item $class-EB($filename, %options) Read the MOT table information from C<$filename>. -Option --Default charset =over 2 =item charset => STRING The character-set which is used for the file. When not specified, it is taken from the "Content-Type" field in the PO-file. =back =back =head2 Attributes Extends L<"Attributes" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Attributes">. =over 4 =item $obj-EB() Returns the name of the source file for this data. =item $obj-EB() Returns a HASH of all defined PO objects, organized by msgid. Please try to avoid using this: use L for lookup. =item $obj-EB() Returns the character-set as found in the PO-file. The strings are converted into utf8 before you use them in the program. =back =head2 Managing PO's Extends L<"Managing PO's" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Managing PO's">. =head3 Translation Extends L<"Translation" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Translation">. =over 4 =item $obj-EB( STRING, [$msgctxt] ) Lookup the translations with the C. Returns a SCALAR, when only one translation is known, and an ARRAY when we have plural forms. Returns C when the translation is not defined. Improves base, see L =item $obj-EB( $msgid, [$count, $msgctxt] ) Returns the translated string for C<$msgid>. When not specified, C<$count> is 1 (the singular form). Improves base, see L =back =head3 Administration Extends L<"Administration" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Administration">. =over 4 =item $obj-EB($po) Inherited, see L =item $obj-EB
($field) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB($count) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB( [$active] ) Inherited, see L =back =head1 DIAGNOSTICS =over 4 =item Error: cannot detect charset in $fn Cast by C =item Fault: cannot read magic from $fn: $! Cast by C =item Fault: cannot read mo from file $fn: $! Cast by C =item Fault: cannot read msgids from $fn, need $size at $loc: $! Cast by C =item Fault: cannot read originals from $fn, need $size at $loc: $! Cast by C =item Fault: cannot read superblock from $fn: $! Cast by C =item Fault: cannot read translations from $fn, need $size at $loc: $! Cast by C =item Fault: cannot read translations from $fn, need $size at $loc: $! Cast by C =item Fault: cannot seek to $loc in $fn for msgid strings: $! Cast by C =item Fault: cannot seek to $loc in $fn for originals: $! Cast by C =item Fault: cannot seek to $loc in $fn for transl strings: $! Cast by C =item Fault: cannot seek to $loc in $fn for translations: $! Cast by C =item Error: invalid plural-form algorithm '$alg' Cast by C =item Error: only acceptable parameter is 'ACTIVE' Cast by C =item Error: the header is not the first entry, needed for charset in $fn Cast by C =item Error: there is no Plural-Forms field in the header, but needed Cast by C =item Error: unsupported charset $charset in $fn Cast by C =item Error: unsupported explicit charset $charset for $fn Cast by C =item Error: unsupported file type (magic number is $magic) Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/POTcompact.pm0000644000175000001440000001031315103071403024251 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Lexicon::POTcompact;{ our $VERSION = '1.15'; } use base 'Log::Report::Lexicon::Table'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use Log::Report::Util qw/escape_chars unescape_chars/; use Encode qw/find_encoding/; sub _unescape($$); sub _escape($$); #-------------------- sub read($@) { my ($class, $fn, %args) = @_; my $charset = $args{charset}; my $self = bless +{}, $class; # Try to pick-up charset from the filename (which may contain a modifier) $charset = $1 if !$charset && $fn =~ m!\.([\w-]+)(?:\@[^/\\]+)?\.po$!i; my $fh; if($charset) { open $fh, "<:encoding($charset):crlf", $fn or fault __x"cannot read in {charset} from file {fn}", charset => $charset, fn => $fn; } else { open $fh, '<:raw:crlf', $fn or fault __x"cannot read from file {fn} (unknown charset)", fn=>$fn; } # Speed! my $msgctxt = ''; my ($last, $msgid, @msgstr); my $index = $self->{index} ||= {}; my $add = sub { unless($charset) { $msgid eq '' or error __x"header not found for charset in {fn}", fn => $fn; $charset = $msgstr[0] =~ m/^content-type:.*?charset=["']?([\w-]+)/mi ? $1 : error __x"cannot detect charset in {fn}", fn => $fn; my $enc = find_encoding($charset) or error __x"unsupported charset {charset} in {fn}", charset => $charset, fn => $fn; trace "auto-detected charset $charset for $fn"; binmode $fh, ":encoding($charset):crlf"; $_ = $enc->decode($_) for @msgstr, $msgctxt; } $index->{"$msgid#$msgctxt"} = @msgstr > 1 ? [@msgstr] : $msgstr[0]; ($msgctxt, $msgid, @msgstr) = (''); }; LINE: while(my $line = $fh->getline) { next if substr($line, 0, 1) eq '#'; if($line =~ m/^\s*$/) # blank line starts new { $add->() if @msgstr; next LINE; } if($line =~ s/^msgctxt\s+//) { $msgctxt = _unescape $line, $fn; $last = \$msgctxt; } elsif($line =~ s/^msgid\s+//) { $msgid = _unescape $line, $fn; $last = \$msgid; } elsif($line =~ s/^msgstr\[(\d+)\]\s*//) { $last = \($msgstr[$1] = _unescape $line, $fn); } elsif($line =~ s/^msgstr\s+//) { $msgstr[0] = _unescape $line, $fn; $last = \$msgstr[0]; } elsif($last && $line =~ m/^\s*\"/) { $$last .= _unescape $line, $fn; } } $add->() if @msgstr; # don't forget the last close $fh or failure __x"failed reading from file {fn}", fn => $fn; $self->{origcharset} = $charset; $self->{filename} = $fn; $self->setupPluralAlgorithm; $self; } #-------------------- sub filename() { $_[0]->{filename} } sub originalCharset() { $_[0]->{origcharset} } #-------------------- sub index() { $_[0]->{index} } # The index is a HASH with "$msg#$msgctxt" keys. If there is no # $msgctxt, then there still is the # sub msgid($) { $_[0]->{index}{$_[1].'#'.($_[2]//'')} } # speed!!! sub msgstr($;$$) { my ($self, $msgid, $count, $ctxt) = @_; $ctxt //= ''; my $po = $self->{index}{"$msgid#$ctxt"} or return undef; ref $po # no plurals defined or return $po; $po->[$self->{algo}->($count // 1)] || $po->[$self->{algo}->(1)]; } # ### internal helper routines, shared with ::PO.pm and ::POT.pm # sub _unescape($$) { unless( $_[0] =~ m/^\s*\"(.*)\"\s*$/ ) { warning __x"string '{text}' not between quotes at {location}", text => $_[0], location => $_[1]; return $_[0]; } unescape_chars $1; } sub _escape($$) { my @escaped = map { '"' . escape_chars($_) . '"' } defined $_[0] && length $_[0] ? split(/(?<=\n)/, $_[0]) : ''; unshift @escaped, '""' if @escaped > 1; join $_[1], @escaped; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/PO.pm0000644000175000001440000002057315103071403022567 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Lexicon::PO;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; # steal from cheaper module, we have no ::Util for this (yet) use Log::Report::Lexicon::POTcompact (); *_escape = \&Log::Report::Lexicon::POTcompact::_escape; *_unescape = \&Log::Report::Lexicon::POTcompact::_unescape; sub flat(@) { grep defined, ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_ } #-------------------- sub new(@) { my $class = shift; (bless {}, $class)->init( {@_} ); } sub init($) { my ($self, $args) = @_; defined($self->{msgid} = delete $args->{msgid}) or error __"no msgid defined for PO"; $self->{plural} = delete $args->{msgid_plural}; $self->{msgstr} = delete $args->{msgstr}; $self->{msgctxt} = delete $args->{msgctxt}; $self->addComment(delete $args->{comment}); $self->addAutomatic(delete $args->{automatic}); $self->fuzzy(delete $args->{fuzzy}); $self->{refs} = {}; $self->addReferences(delete $args->{references}) if defined $args->{references}; $self; } # only for internal usage sub _fast_new($) { bless $_[1], $_[0] } #-------------------- sub msgid() { $_[0]->{msgid} } sub msgctxt() { $_[0]->{msgctxt} } sub plural(;$) { my $self = shift; @_ or return $self->{plural}; if(my $m = $self->{msgstr}) { # prepare msgstr list for multiple translations. $self->{msgstr} = [ $m ] if defined $m && !ref $m; } $self->{plural} = shift; } sub msgstr($;$) { my $self = shift; my $m = $self->{msgstr}; unless($self->{plural}) { $self->{msgstr} = $_[1] if @_==2; return $m; } my $index = shift || 0; @_ ? $m->[$index] = shift : $m->[$index]; } sub comment(@) { my $self = shift; @_ or return $self->{comment}; $self->{comment} = ''; $self->addComment(@_); } sub addComment(@) { my $self = shift; my @lines = flat @_; my $comment = $self->{comment}; foreach my $line (@lines) { defined $line or next; $line =~ s/[\r\n]+/\n/; # cleanup line-endings $comment .= $line; } # be sure there is a \n at the end $comment =~ s/\n?\z/\n/ if defined $comment; $self->{comment} = $comment; } sub automatic(@) { my $self = shift; @_ or return $self->{automatic}; $self->{automatic} = ''; $self->addAutomatic(@_); } sub addAutomatic(@) { my $self = shift; my @lines = flat @_; my $auto = $self->{automatic}; foreach my $line (@lines) { $line =~ s/[\r\n]+/\n/; # cleanup line-endings $auto .= $line; } $auto =~ s/\n?\z/\n/ if defined $auto; # be sure there is a \n at the end $self->{automatic} = $auto; } sub references(@) { my $self = shift; if(@_) { $self->{refs} = +{ }; $self->addReferences(@_); } keys %{$self->{refs}}; } sub addReferences(@) { my $self = shift; my $refs = $self->{refs} ||= {}; my @new = @_==1 && defined $_[0] && ref $_[0] ne 'ARRAY' ? split(" ", $_[0]) : flat @_; $refs->{$_}++ for @new; $refs; } sub removeReferencesTo($) { my $refs = $_[0]->{refs}; my $match = qr/^\Q$_[1]\E\:[0-9]+$/; $_ =~ $match && delete $refs->{$_} for keys %$refs; scalar keys %$refs; } sub keepReferencesTo($) { my $refs = shift->{refs}; my $keep = shift; foreach my $ref (keys %$refs) { (my $fn = $ref) =~ s/\:[0-9]+$//; $keep->{$fn} or delete $refs->{$ref}; } scalar keys %$refs; } sub isActive() { $_[0]->{msgid} eq '' || keys %{$_[0]->{refs}} } sub fuzzy(;$) { my $self = shift; @_ ? $self->{fuzzy} = shift : $self->{fuzzy} } sub format(@) { my $format = shift->{format}; return $format->{ (shift) } if @_==1 && !ref $_[0]; # language my @pairs = ref $_[0] eq 'HASH' ? %{$_[0]} : flat @_; while(@pairs) { my($k, $v) = (shift @pairs, shift @pairs); $format->{$k} = $v; } $format; } sub addFlags($) { my $self = shift; local $_ = shift; my $where = shift; s/^\s+//; s/\s*$//; foreach my $flag (split /\s*\,\s*/) { if($flag eq 'fuzzy') { $self->fuzzy(1) } elsif($flag =~ m/^no-(.*)-format$/) { $self->format($1, 0) } elsif($flag =~ m/^(.*)-format$/) { $self->format($1, 1) } else { warning __x"unknown flag {flag} ignored", flag => $flag; } } $_; } #-------------------- sub fromText($$) { my $class = shift; my @lines = split /[\r\n]+/, shift; my $where = shift || ' unknown location'; my $self = bless +{}, $class; # translations which are not used anymore are escaped with #~ # however, we just say: no references found. s/^\#\~\s+// for @lines; my $last; # used for line continuations foreach (@lines) { s/\r?\n$//; if( s/^\#(.)\s?// ) { if($1 =~ /\s/) { $self->addComment($_) } elsif($1 eq '.' ) { $self->addAutomatic($_) } elsif($1 eq ':' ) { $self->addReferences($_) } elsif($1 eq ',' ) { $self->addFlags($_) } else { warning __x"unknown comment type '{cmd}' at {where}", cmd => "#$1", where => $where; } undef $last; } elsif( s/^\s*(\w+)\s+// ) { my $cmd = $1; my $string = _unescape($_,$where); if($cmd eq 'msgid') { $self->{msgid} = $string; $last = \($self->{msgid}); } elsif($cmd eq 'msgid_plural') { $self->{plural} = $string; $last = \($self->{plural}); } elsif($cmd eq 'msgstr') { $self->{msgstr} = $string; $last = \($self->{msgstr}); } elsif($cmd eq 'msgctxt') { $self->{msgctxt} = $string; $last = \($self->{msgctxt}); } else { warning __x"do not understand command '{cmd}' at {where}", cmd => $cmd, where => $where; undef $last; } } elsif( s/^\s*msgstr\[(\d+)\]\s*// ) { my $nr = $1; $self->{msgstr}[$nr] = _unescape($_,$where); } elsif( m/^\s*\"/ ) { if(defined $last) { $$last .= _unescape($_, $where) } else { warning __x"quoted line is not a continuation at {where}", where => $where; } } else { warning __x"do not understand line at {where}:\n {line}", where => $where, line => $_; } } defined $self->{msgid} or warning __x"no msgid in block {where}", where => $where; $self; } sub toString(@) { my ($self, %args) = @_; my $nplurals = $args{nr_plurals}; my @record; my $comment = $self->comment; if(defined $comment && length $comment) { $comment =~ s/^/# /gm; push @record, $comment; } my $auto = $self->automatic; if(defined $auto && length $auto) { $auto =~ s/^/#. /gm; push @record, $auto; } my @refs = sort $self->references; my $msgid = $self->{msgid} || ''; my $active = $msgid eq '' || @refs ? '' : '#~ '; while(@refs) { my $line = '#:'; $line .= ' '.shift @refs while @refs && length($line) + length($refs[0]) < 80; push @record, "$line\n"; } my @flags = $self->{fuzzy} ? 'fuzzy' : (); push @flags, ($self->{format}{$_} ? '' : 'no-') . $_ . '-format' for sort keys %{$self->{format}}; push @record, "#, ". join(", ", @flags) . "\n" if @flags; my $msgctxt = $self->{msgctxt}; if(defined $msgctxt && length $msgctxt) { push @record, "${active}msgctxt "._escape($msgctxt, "\n$active")."\n"; } push @record, "${active}msgid "._escape($msgid, "\n$active")."\n"; my $msgstr = $self->{msgstr} || []; my @msgstr = ref $msgstr ? @$msgstr : $msgstr; my $plural = $self->{plural}; if(defined $plural) { push @record, "${active}msgid_plural " . _escape($plural, "\n$active") . "\n"; push @msgstr, '' while defined $nplurals && @msgstr < $nplurals; if(defined $nplurals && @msgstr > $nplurals) { warning __x"too many plurals for '{msgid}'", msgid => $msgid; $#msgstr = $nplurals -1; } $nplurals ||= 2; for(my $nr = 0; $nr < $nplurals; $nr++) { push @record, "${active}msgstr[$nr] " . _escape($msgstr[$nr], "\n$active") . "\n"; } } else { warning __x"no plurals for '{msgid}'", msgid => $msgid if @msgstr > 1; push @record, "${active}msgstr " . _escape($msgstr[0], "\n$active") . "\n"; } join '', @record; } sub useless() { my $self = shift; ! $self->references && ! $self->msgstr(0); } *unused = \&useless; # before <1.02 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/POT.pod0000644000175000001440000002276415103071404023066 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::POT - manage PO files =head1 INHERITANCE Log::Report::Lexicon::POT is a Log::Report::Lexicon::Table =head1 SYNOPSIS # this is usually not for end-users, See ::Extract::PerlPPI # using a PO table my $pot = Log::Report::Lexicon::POT->read('po/nl.po', charset => 'utf-8') or die; my $po = $pot->msgid('msgid'); my $po = $pot->msgid($msgid, $msgctxt); print $pot->nrPlurals; print $pot->msgstr('msgid', 3); print $pot->msgstr($msgid, 3, $msgctxt); $pot->write; # update the file # fill the table, by calling the next a lot my $po = Log::Report::Lexicon::PO->new(...); $pot->add($po); # creating a PO table $pot->write('po/nl.po') or die; =head1 DESCRIPTION This module is reading, extending, and writing POT files. POT files are used to store translations in humanly readable format for most of existing translation frameworks, like GNU gettext and Perl's Maketext. If you only wish to access the translation, then you may use the much more efficient L. The code is loosely based on Locale::PO, by Alan Schwartz. The coding style is a bit off the rest of C, and there was a need to sincere simplification. Each PO record will be represented by a L. Extends L<"DESCRIPTION" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"DESCRIPTION">. =head1 METHODS Extends L<"METHODS" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"METHODS">. =head2 Constructors Extends L<"Constructors" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Constructors">. =over 4 =item $class-EB(%options) Create a new POT file. The initial header is generated for you, but it can be changed using the L method. -Option --Default charset 'UTF-8' date now filename undef index {} nr_plurals 2 plural_alg n!=1 plural_forms textdomain version undef =over 2 =item charset => STRING The charset to be used for the createed file. It is unwise to use anything else than 'UTF-8', but allowed. Before [1.09] this option was required. =item date => STRING Overrule the date which is included in the generated header. =item filename => STRING Specify an output filename. The name can also be specified when L is called. =item index => HASH A set of translations (L objects), with msgid as key. =item nr_plurals => INTEGER The number of translations each of the translation with plural form need to have. =item plural_alg => EXPRESSION The algorithm to be used to calculate which translated msgstr to use. =item plural_forms => RULE [0.992] When this option is used, it overrules C and C. The RULE should be a full "Plural-Forms" field. =item textdomain => STRING The package name, used in the directory structure to store the PO files. =item version => STRING =back =item $class-EB($filename, %options) Read the POT information from C<$filename>. -Option --Default charset =over 2 =item charset => STRING The character-set which is used for the file. You must specify this explicitly. =back =item $obj-EB( [$filename|$fh], %options ) When you pass an open C<$fh>, you are yourself responsible that the correct character-encoding (binmode) is set. When the write followed a L or the filename was explicitly set with L, then you may omit the first parameter. -Option --Default only_active false =over 2 =item only_active => BOOLEAN [1.02] Do not write records which do have a translation, but where the msgid has disappeared from the sources. By default, these records are commented out (marked with '#~') but left in the file. =back =back =head2 Attributes Extends L<"Attributes" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Attributes">. =over 4 =item $obj-EB() The character-set to be used for reading and writing. You do not need to be aware of Perl's internal encoding for the characters. =item $obj-EB() Returns the filename, as derived from L or specified during initiation with L. =item $obj-EB() Returns a HASH of all defined PO objects, organized by msgid. Please try to avoid using this: use L for lookup and L for adding translations. =item $obj-EB() Returns the language code, which is derived from the filename. =back =head2 Managing PO's Extends L<"Managing PO's" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Managing PO's">. =over 4 =item $obj-EB($table) Remove all references which are not found as key in the hash C<$table>. Returns the number of references left. =item $obj-EB($filename) Remove all the references to the indicate C<$filename> from all defined translations. Returns the number of refs left. =item $obj-EB() Returns a HASH with some statistics about this POT table. =item $obj-EB( [$date] ) Replace the "PO-Revision-Date" with the specified C<$date>, or the current moment. =back =head3 Translation Extends L<"Translation" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Translation">. =over 4 =item $obj-EB( STRING, [$msgctxt] ) Lookup the L with the C. If you want to add a new translation, use L. Returns C when not defined. Improves base, see L =item $obj-EB( $msgid, [$count, [$msgctxt]] ) Returns the translated string for C<$msgid>. When C<$count> is not specified or C, the translation string related to "1" is returned. Improves base, see L =back =head3 Administration Extends L<"Administration" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Administration">. =over 4 =item $obj-EB($po) Add the information from a C<$po> into this POT. If the msgid of the C<$po> is already known, that is an error. Improves base, see L =item $obj-EB
( [$field, [$content]] ) The translation of a blank MSGID is used to store a MIME header, which contains some meta-data. When only a C<$field> is specified, that content is looked-up (case-insensitive) and returned. When a C<$content> is specified, the knowledge will be stored. In latter case, the header structure may get created. When the C<$content> is set to C, the field will be removed. Improves base, see L =item $obj-EB() Inherited, see L =item $obj-EB($count) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB( [$active] ) Returns a list with all defined L objects. When the string C<$active> is given as parameter, only objects which have references are returned. Improves base, see L =back =head1 DIAGNOSTICS =over 4 =item Error: cannot detect charset in $fn Cast by C =item Fault: cannot read from file $fn (unknown charset): $! Cast by C =item Fault: cannot read in $cs from file $fn: $! Cast by C =item Fault: cannot write to file $fn with $layers: $! Cast by C =item Fault: failed reading from file $fn: $! Cast by C =item Error: invalid plural-form algorithm '$alg' Cast by C =item Error: no filename or file-handle specified for PO When a PO file is written, then a filename or file-handle must be specified explicitly, or set beforehand using the L method, or known because the write follows a L of the file. Cast by C =item Error: no filename or file-handle specified for PO Cast by C =item Error: no header defined in POT for file $fn Cast by C =item Error: textdomain parameter is required Cast by C =item Error: the only acceptable parameter is 'ACTIVE', not '$p' Cast by C =item Error: there is no Plural-Forms field in the header, but needed Cast by C =item Error: translation already exists for '$msgid' with '$ctxt Cast by C =item Error: unsupported charset $charset in $fn Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/Index.pm0000644000175000001440000001037415103071403023316 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! #oorestyle: old style disclaimer to be removed. # This code is part of distribution Log-Report-Lexicon. Meta-POD processed # with OODoc into POD and HTML manual-pages. See README.md # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. package Log::Report::Lexicon::Index;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; use Log::Report::Util qw/parse_locale/; use File::Find (); # The next two need extension when other lexicon formats are added sub _understand_file_format($) { $_[0] =~ qr/\.(?:gmo|mo|po)$/i } sub _find($$) { my ($index, $name) = (shift, lc shift); $index->{"$name.mo"} || $index->{"$name.gmo"} || $index->{"$name.po"}; # prefer mo } # On windows, other locale names are used. They will get translated # into the Linux (ISO) convensions. my $locale_unifier; if($^O eq 'MSWin32') { require Log::Report::Win32Locale; Log::Report::Win32Locale->import; $locale_unifier = sub { iso_locale($_[0]) }; } else { # some UNIXes do not understand "POSIX" $locale_unifier = sub { uc $_[0] eq 'POSIX' ? 'c' : lc $_[0] }; } #-------------------- sub new($;@) { my ($class, $dir) = (shift, shift); bless +{ dir => $dir, @_ }, $class; # dir before first argument. } #-------------------- sub directory() { $_[0]->{dir} } #-------------------- sub index() { my $self = shift; return $self->{index} if exists $self->{index}; my $dir = $self->directory; my $strip_dir = qr!\Q$dir/!; $self->{index} = {}; File::Find::find( +{ wanted => sub { -f && !m[/\.] && _understand_file_format($_) or return 1; (my $key = $_) =~ s/$strip_dir//; $self->addFile($key, $_); 1; }, follow => 1, no_chdir => 1, follow_skip => 2 }, $dir); $self->{index}; } sub addFile($;$) { my ($self, $base, $abs) = @_; $abs ||= File::Spec->catfile($self->directory, $base); $base =~ s!\\!/!g; # dos->unix $self->{index}{lc $base} = $abs; } sub find($$) { my $self = shift; my $domain = lc shift; my $locale = $locale_unifier->(shift); my $index = $self->index; keys %$index or return undef; my ($lang, $terr, $cs, $modif) = parse_locale $locale; unless(defined $lang) { defined $locale or $locale = ''; # avoid problem with recursion, not translatable! print STDERR "illegal locale $locale, when looking for $domain"; return undef; } $terr = defined $terr ? '_'.$terr : ''; $cs = defined $cs ? '.'.$cs : ''; $modif = defined $modif ? '@'.$modif : ''; (my $normcs = $cs) =~ s/[^a-z0-9]//g; if(length $normcs) { $normcs = "iso$normcs" if $normcs !~ /[^0-9-]/; $normcs = '.'.$normcs; } my $fn; for my $f ("/lc_messages/$domain", "/$domain") { $fn ||= _find($index, "$lang$terr$cs$modif$f") || _find($index, "$lang$terr$normcs$modif$f") || _find($index, "$lang$terr$modif$f") || _find($index, "$lang$modif$f") || _find($index, "$lang$f"); } $fn || _find($index, "$domain/$lang$terr$cs$modif") || _find($index, "$domain/$lang$terr$normcs$modif") || _find($index, "$domain/$lang$terr$modif") || _find($index, "$domain/$lang$cs$modif") || _find($index, "$domain/$lang$normcs$modif") || _find($index, "$domain/$lang$modif") || _find($index, "$domain/$lang"); } sub list($;$) { my $self = shift; my $domain = lc shift; my $filter = shift; my $index = $self->index; my @list = map $index->{$_}, grep m!\b\Q$domain\E\b!, keys %$index; defined $filter or return @list; $filter = qr/\.\Q$filter\E$/i if defined $filter && ref $filter ne 'Regexp'; grep $_ =~ $filter, @list; } #-------------------- 1; Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/PO.pod0000644000175000001440000001447015103071404022735 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::PO - one translation definition =head1 SYNOPSIS =head1 DESCRIPTION This module is administering one translation object. Sets of PO records are kept in a POT file, implemented in L. =head1 METHODS =head2 Constructors =over 4 =item $class-EB(%options) Z<> -Option --Default automatic "" comment [] format [] fuzzy false msgctxt undef msgid msgid_plural undef msgstr "" or [] references [] =over 2 =item automatic => PARAGRAPH Automatically added comments. See L. =item comment => PARAGRAPH Translator added comments. See L. =item format => ARRAY|HASH See L. Either an ARRAY with PAIRS or a HASH with that same information. =item fuzzy => BOOLEAN The string is not yet translated, some smart guesses may have been made. See L. =item msgctxt => STRING Context string: text around the msgid itself. =item msgid => STRING =item msgid_plural => STRING =item msgstr => STRING|ARRAY-OF-STRING The translations for the msgid. When msgid_plural is defined, then an ARRAY must be provided. =item references => STRING|ARRAY-OF-LOCATIONS The STRING is a blank separated list of LOCATIONS. LOCATIONs are of the form C, for instance C See L =back =back =head2 Attributes =over 4 =item $obj-EB(LIST|ARRAY|STRING) Add multiple lines to the translator's comment block. Returns an empty string if there are no comments. =item $obj-EB(LIST|ARRAY|STRING) Add multiple lines to the translator's comment block. Returns an empty string if there are no comments. =item $obj-EB(STRING) Parse a "flags" line. =item $obj-EB(STRING|LIST|ARRAY) The C is a blank separated list of LOCATIONS. The C and C contain separate LOCATIONs. A LOCATION is of the form C. Returns the internal HASH with references. =item $obj-EB( [LIST|ARRAY|STRING] ) Returns a C which contains the cleaned paragraph of automatically added comments. If an argument is specified, it will replace the current comment. =item $obj-EB( [LIST|ARRAY|STRING] ) Returns a C which contains the cleaned paragraph of translator's comment. If an argument is specified, it will replace the current comment. =item $obj-EB( $language | ) When one C<$language> is specified, it looks whether a "language-format" or "no-language-format" is present in the line of FLAGS. This will return C<1> (C) in the first case, C<0> (C) in the second case. It will return C (also C) in case that both are not present. You can also specify C: the key is a language name, and the value is either C<0>, C<1>, or C. » example: use of format() # getters if($po->format('c')) ... unless($po->format('perl-brace')) ... if(defined $po->format('java')) ... # setters $po->format(java => 1); # results in 'java-format' $po->format(java => 0); # results in 'no-java-format' $po->format(java => undef); # results in '' =item $obj-EB( [BOOLEAN] ) Returns whether the translation needs human inspection. =item $obj-EB() Returns whether the translation has any references, or is the header. =item $obj-EB($table) Remove all references which are not found as key in the hash C<$table>. Returns the number of references left. =item $obj-EB() Returns the message context, if provided. =item $obj-EB() Returns the actual msgid, which cannot be C. =item $obj-EB( [$index, [STRING]] ) With a C, a new translation will be set. Without C, a lookup will take place. When no plural is defined, the C<$index> is ignored. =item $obj-EB( [STRING] ) Returns the actual msgid_plural, which can be C. =item $obj-EB( [STRING|LIST|ARRAY] ) Returns an unsorted list of LOCATIONS. When options are specified, then those will be used to replace all currently defined references. Returns the unsorted C of references. =item $obj-EB($filename) Remove all the references to the indicate C<$filename> from the list. Returns the number of refs left. =back =head2 Parsing =over 4 =item $class-EB( STRING, [$where] ) Parse the C into a new PO object. The C<$where> string should explain the location of the C, to be used in error messages. =item $obj-EB(%options) Format the object into a multi-lined string. -Option --Default nr_plurals undef =over 2 =item nr_plurals => INTEGER If the number of plurals is specified, then the plural translation list can be checked for the correct length. Otherwise, no smart behavior is attempted. =back =item $obj-EB() [1.02] The message-id has no references anymore B no translations. =back =head1 DIAGNOSTICS =over 4 =item Warning: do not understand command '$cmd' at $where Cast by C =item Warning: do not understand line at $where:\n $line Cast by C =item Error: no msgid defined for PO Cast by C =item Warning: no msgid in block $where Cast by C =item Warning: no plurals for '$msgid' Cast by C =item Warning: quoted line is not a continuation at $where Cast by C =item Warning: too many plurals for '$msgid' Cast by C =item Warning: unknown comment type '$cmd' at $where Cast by C =item Warning: unknown flag $flag ignored Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/POTcompact.pod0000644000175000001440000001124715103071404024427 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::POTcompact - use translations from a POT file =head1 INHERITANCE Log::Report::Lexicon::POTcompact is a Log::Report::Lexicon::Table =head1 SYNOPSIS # using a PO table efficiently my $pot = Log::Report::Lexicon::POTcompact->read('po/nl.po') or die; my $header = $pot->msgid(''); print $pot->msgstr('msgid', 3); =head1 DESCRIPTION This module is translating, based on PO files. PO files are used to store translations in humanly readable format for most of existing translation frameworks, like GNU gettext and Perl's Maketext. Internally, this module tries to be as efficient as possible: high speed and low memory foot-print. You will not be able to sub-class this class cleanly. If you like to change the content of PO files, then use L. Extends L<"DESCRIPTION" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"DESCRIPTION">. =head1 METHODS Extends L<"METHODS" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"METHODS">. =head2 Constructors Extends L<"Constructors" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Constructors">. =over 4 =item $class-EB(%options) Inherited, see L =item $class-EB($filename, %options) Read the POT table information from C<$filename>, as compact as possible. Comments, plural-form, and such are lost on purpose: they are not needed for translations. -Option --Default charset undef =over 2 =item charset => STRING When the charset is not specified, it will be taken from the content-type field in the po-file header. =back =back =head2 Attributes Extends L<"Attributes" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Attributes">. =over 4 =item $obj-EB() Returns the name of the source file for this data. =item $obj-EB() [1.09] Returns the character-set of the strings found in the file. They will get translated into utf8 before being used in Perl. =back =head2 Managing PO's Extends L<"Managing PO's" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Managing PO's">. =head3 Translation Extends L<"Translation" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Translation">. =over 4 =item $obj-EB( STRING, [$msgctxt] ) Lookup the translations with the C. Returns a SCALAR, when only one translation is known, and an ARRAY wherein there are multiple. Returns C when the translation is not defined. Improves base, see L =item $obj-EB( $msgid, [$count, [$msgctxt] ) Returns the translated string for C<$msgid>. When not specified, C<$count> is 1 (the single form). Improves base, see L =back =head3 Administration Extends L<"Administration" in Log::Report::Lexicon::Table|Log::Report::Lexicon::Table/"Administration">. =over 4 =item $obj-EB($po) Inherited, see L =item $obj-EB
($field) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB($count) Inherited, see L =item $obj-EB() Inherited, see L =item $obj-EB( [$active] ) Inherited, see L =back =head1 DIAGNOSTICS =over 4 =item Error: cannot detect charset in $fn Cast by C =item Fault: cannot read from file $fn (unknown charset): $! Cast by C =item Fault: cannot read in $charset from file $fn: $! Cast by C =item Error: header not found for charset in $fn Cast by C =item Error: invalid plural-form algorithm '$alg' Cast by C =item Error: only acceptable parameter is 'ACTIVE' Cast by C =item Warning: string '$text' not between quotes at $location Cast by C =item Error: there is no Plural-Forms field in the header, but needed Cast by C =item Error: unsupported charset $charset in $fn Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/Table.pod0000644000175000001440000000671215103071404023446 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::Table - generic interface to translation tables =head1 INHERITANCE Log::Report::Lexicon::Table is extended by Log::Report::Lexicon::MOTcompact Log::Report::Lexicon::POT Log::Report::Lexicon::POTcompact =head1 SYNOPSIS # use one of the extensions, for instance: my $pot = Log::Report::Lexicon::POT->read('po/nl.po', charset => 'utf-8') or panic; =head1 DESCRIPTION This base class defines the generic interface for translation tables. Currently, there are three extensions: =over 4 =item * L This is a relatively heavy implementation, used to read but also to write PO files. It is used by F, for instance, to administer the collection of discovered msgid's. =item * L Light-weighted read-only access to PO-file information. =item * L Read-only access to MO-file information. These binary MO-files are super efficient. =back =head1 METHODS =head2 Constructors =over 4 =item $class-EB(%options) Z<> =back =head2 Attributes =head2 Managing PO's =head3 Translation =over 4 =item $obj-EB( STRING, [$msgctxt] ) Lookup the L with the C. Returns C when not defined. =item $obj-EB( $msgid, [$count, $msgctxt] ) Returns the translated string for C<$msgid>. When not specified, C<$count> is 1. =back =head3 Administration =over 4 =item $obj-EB($po) Add the information from a C<$po> into this POT. If the msgid of the C<$po> is already known, that is an error. =item $obj-EB
($field) The translation of a blank MSGID is used to store a MIME header, which contains some meta-data. The C<$field> value is looked-up (case-insensitive) and returned. =item $obj-EB() Returns the number of plurals, when not known then '2'. =item $obj-EB($count) Returns the msgstr index used to translate a value of C<$count>. =item $obj-EB() This method needs to be called after setting (reading or creating) a new table header, to interpret the plural algorithm as specified in the C header field. [1.09] The header field is not required when not used. A full list of plural forms per language can be found at L =item $obj-EB( [$active] ) Returns a list with all defined L objects. When the string C<$active> is given as parameter, only objects which have references are returned. =back =head1 DIAGNOSTICS =over 4 =item Error: invalid plural-form algorithm '$alg' Cast by C =item Error: only acceptable parameter is 'ACTIVE' Cast by C =item Error: there is no Plural-Forms field in the header, but needed Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/Index.pod0000644000175000001440000001507015103071404023463 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon::Index - search through available translation files =head1 SYNOPSIS my $index = Log::Report::Lexicon::Index->new($directory); my $fn = $index->find('my-domain', 'nl_NL.utf-8'); =head1 DESCRIPTION This module handles the lookup of translation files for a whole directory tree. It is lazy loading, which means that it will only build the search tree when addressed, not when the object is created. =head1 METHODS =head2 Constructors =over 4 =item $class-EB($directory, %options) Create an index for a certain directory. If the directory does not exist or is empty, then the object will still be created. All files the C<$directory> tree which are recognized as an translation table format which is understood will be listed. Momentarily, those are: =over =item . files with extension "po", see L =item . [0.993] files with extension "mo", see L =back [0.99] Files which are in directories which start with a dot (hidden directories) and files which start with a dot (hidden files) are skipped. =back =head2 Accessors =over 4 =item $obj-EB() Returns the directory name. =back =head2 Search =over 4 =item $obj-EB( $basename, [$absolute] ) Add a certain file to the index. This method returns the C<$absolute> path to that file, which must be used to access it. When not explicitly specified, the C<$absolute> path will be calculated. =item $obj-EB($textdomain, $locale) Lookup the best translation table, according to the rules described in chapter L, below. Returned is a filename, or C if nothing is defined for the C<$locale> (there is no default on this level). =item $obj-EB() For internal use only. Force the creation of the index (if not already done). Returns a hash with key-value pairs, where the key is the lower-cased version of the filename, and the value the case-sensitive version of the filename. =item $obj-EB( $domain, [$extension] ) Returned is a list of filenames which is used to update the list of MSGIDs when source files have changed. All translation files which belong to a certain C<$domain> are listed. The C<$extension> filter can be used to reduce the filenames further, for instance to select only C, C or C files, and ignore readme's. Use an string, without dot and interpreted case-insensitive, or a regular expression. » example: my @l = $index->list('my-domain'); my @l = $index->list('my-domain', 'po'); my @l = $index->list('my-domain', qr/^readme/i); =back =head1 DETAILS It's always complicated to find the lexicon files, because the perl package can be installed on any weird operating system. Therefore, you may need to specify the lexicon directory or alternative directories explicitly. However, you may also choose to install the lexicon files in between the perl modules. =head2 merge lexicon files with perl modules By default, the filename which contains the package which contains the textdomain's translator configuration is taken (that can be only one) and changed into a directory name. The path is then extended with C to form the root of the lexicon: the top of the index. After this, the locale indication, the lc-category (usually LC_MESSAGES), and the C followed by C<.po> are added. This is exactly as C does, but then using the PO text file instead of the MO binary file. =head4 » Example: lexicon in module tree My module is named C and installed in some of perl's directories, say C<~perl5.8.8>. The module is defining textdomain C. The translation is made into C (locale for Dutch spoken in The Netherlands, utf-8 encoded text file). The default location for the translation table is under ~perl5.8.8/Some/Module/messages/ for instance ~perl5.8.8/Some/Module/messages/nl-NL.utf-8/LC_MESSAGES/my-domain.po There are alternatives, as described in L, for instance ~perl5.8.8/Some/Module/messages/my-domain/nl-NL.utf-8.po ~perl5.8.8/Some/Module/messages/my-domain/nl.po =head2 Locale search The exact gettext defined format of the locale is language[_territory[.codeset]][@modifier] The modifier will be used in above directory search, but only if provided explicitly. The manual C determines the rules. During the search, components of the locale get stripped, in the following order: =over 4 =item 1. codeset =item 2. normalized codeset =item 3. territory =item 4. modifier =back The normalized codeset (character-set name) is derived by =over 4 =item 1. Remove all characters beside numbers and letters. =item 2. Fold letters to lowercase. =item 3. If the same only contains digits prepend the string "iso". =back To speed-up the search for the right table, the full directory tree will be indexed only once when needed the first time. The content of all defined lexicon directories will get merged into one tree. =head2 Example My module is named C and installed in some of perl's directories, say C<~perl5>. The module is defining textdomain C. The translation is made into C (locale for Dutch spoken in The Netherlands, utf-8 encoded text file). The translation table is taken from the first existing of these files: nl-NL.utf-8/LC_MESSAGES/my-domain.po nl-NL.utf-8/LC_MESSAGES/my-domain.po nl-NL.utf8/LC_MESSAGES/my-domain.po nl-NL/LC_MESSAGES/my-domain.po nl/LC_MESSAGES/my-domain.po Then, attempts are made which are not compatible with gettext. The advantage is that the directory structure is much simpler. The idea is that each domain has its own locale installation directory, instead of everything merged in one place, what gettext presumes. In order of attempts: nl-NL.utf-8/my-domain.po nl-NL.utf8/my-domain.po nl-NL/my-domain.po nl/my-domain.po my-domain/nl-NL.utf8.po my-domain/nl-NL.po my-domain/nl.po Filenames may get mutulated by the platform (which we will try to hide from you [please help improve this]), and are treated case-INsensitive! =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon/MOTcompact.pm0000644000175000001440000001413715103071403024256 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Lexicon::MOTcompact;{ our $VERSION = '1.15'; } use base 'Log::Report::Lexicon::Table'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use Fcntl qw/SEEK_SET/; use Encode qw/find_encoding/; use constant MAGIC_NUMBER => 0x95_04_12_DE; #-------------------- sub read($@) { my ($class, $fn, %args) = @_; my $charset = $args{charset}; $charset = $1 if !$charset && $fn =~ m!\.([\w-]+)(?:\@[^/\\]+)?\.g?mo$!i; my $enc; if(defined $charset) { $enc = find_encoding($charset) or error __x"unsupported explicit charset {charset} for {fn}", charset => $charset, fn => $fn; } my (%index, %locs); my %self = +( index => \%index, # fully prepared ::PO objects locs => \%locs, # know where to find it filename => $fn, ); my $self = bless \%self, $class; my $fh; open $fh, "<:raw", $fn or fault __x"cannot read mo from file {fn}", fn => $fn; # The magic number will tell us the byte-order # See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html # Found in a bug-report that msgctxt are prepended to the msgid with # a separating EOT (4) my ($magic, $superblock, $originals, $translations); CORE::read $fh, $magic, 4 or fault __x"cannot read magic from {fn}", fn => $fn; my $byteorder = $magic eq pack('V', MAGIC_NUMBER) ? 'V' : $magic eq pack('N', MAGIC_NUMBER) ? 'N' : error __x"unsupported file type (magic number is {magic%x})", magic => $magic; # The superblock contains pointers to strings CORE::read $fh, $superblock, 6*4 # 6 times a 32 bit int or fault __x"cannot read superblock from {fn}", fn => $fn; my ($format_rev, $nr_strings, $offset_orig, $offset_trans, $size_hash, $offset_hash) = unpack $byteorder x 6, $superblock; # warn "($format_rev, $nr_strings, $offset_orig, $offset_trans # , $size_hash, $offset_hash)"; # Read location of all originals seek $fh, $offset_orig, SEEK_SET or fault __x"cannot seek to {loc} in {fn} for originals", loc => $offset_orig, fn => $fn; CORE::read $fh, $originals, $nr_strings*8 # each string 2*4 bytes or fault __x"cannot read originals from {fn}, need {size} at {loc}", fn => $fn, loc => $offset_orig, size => $nr_strings*4; my @origs = unpack $byteorder.'*', $originals; # Read location of all translations seek $fh, $offset_trans, SEEK_SET or fault __x"cannot seek to {loc} in {fn} for translations", loc => $offset_orig, fn => $fn; CORE::read $fh, $translations, $nr_strings*8 # each string 2*4 bytes or fault __x"cannot read translations from {fn}, need {size} at {loc}", fn => $fn, loc => $offset_trans, size => $nr_strings*4; my @trans = unpack $byteorder.'*', $translations; # We need the originals as index to the translations (unless there # is a HASH build-in... which is not defined) # The strings are strictly ordered, the spec tells me, to allow binary # search. Better swiftly process the whole block into a hash. my ($orig_start, $orig_end) = ($origs[1], $origs[-1]+$origs[-2]); seek $fh, $orig_start, SEEK_SET or fault __x"cannot seek to {loc} in {fn} for msgid strings", loc => $orig_start, fn => $fn; my ($orig_block, $trans_block); my $orig_block_size = $orig_end - $orig_start; CORE::read $fh, $orig_block, $orig_block_size or fault __x"cannot read msgids from {fn}, need {size} at {loc}", fn => $fn, loc => $orig_start, size => $orig_block_size; my ($trans_start, $trans_end) = ($trans[1], $trans[-1]+$trans[-2]); seek $fh, $trans_start, SEEK_SET or fault __x"cannot seek to {loc} in {fn} for transl strings", loc => $trans_start, fn => $fn; my $trans_block_size = $trans_end - $trans_start; CORE::read $fh, $trans_block, $trans_block_size or fault __x"cannot read translations from {fn}, need {size} at {loc}", fn => $fn, loc => $trans_start, size => $trans_block_size; while(@origs) { my ($id_len, $id_loc) = (shift @origs, shift @origs); my $msgid_b = substr $orig_block, $id_loc-$orig_start, $id_len; my $msgctxt_b = $msgid_b =~ s/(.*)\x04// ? $1 : ''; my ($trans_len, $trans_loc) = (shift @trans, shift @trans); my $msgstr_b = substr $trans_block, $trans_loc - $trans_start, $trans_len; unless(defined $charset) { $msgid_b eq '' or error __x"the header is not the first entry, needed for charset in {fn}", fn => $fn; $charset = $msgstr_b =~ m/^content-type:.*?charset=["']?([\w-]+)/mi ? $1 : error __x"cannot detect charset in {fn}", fn => $fn; trace "auto-detected charset $charset for $fn"; $enc = find_encoding($charset) or error __x"unsupported charset {charset} in {fn}", charset => $charset, fn => $fn; } my $msgid = $enc->decode($msgid_b); my $msgctxt = $enc->decode($msgctxt_b); my @msgstr = map $enc->decode($_), split /\0x00/, $msgstr_b; $index{"$msgid#$msgctxt"} = @msgstr > 1 ? \@msgstr : $msgstr[0]; } close $fh or failure __x"failed reading from file {fn}", fn => $fn; $self->{origcharset} = $charset; $self->setupPluralAlgorithm; $self; } #-------------------- sub index() { $_[0]->{index} } sub filename() { $_[0]->{filename} } sub originalCharset() { $_[0]->{origcharset} } #-------------------- sub msgid($;$) { my ($self, $msgid, $msgctxt) = @_; my $tag = $msgid.'#'.($msgctxt//''); $self->{index}{$tag}; } sub msgstr($;$$) { my $po = $_[0]->msgid($_[1], $_[3]) or return undef; ref $po # no plurals defined or return $po; # speed!!! $po->[$_[0]->{algo}->(defined $_[2] ? $_[2] : 1)] || $po->[$_[0]->{algo}->(1)]; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Translator/0000755000175000001440000000000015103071406022437 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/Translator/Gettext.pod0000644000175000001440000000460615103071404024573 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Translator::Gettext - the GNU gettext infrastructure =head1 INHERITANCE Log::Report::Translator::Gettext is a Log::Report::Translator =head1 SYNOPSIS # normal use (end-users view) textdomain 'my-domain', translator => Log::Report::Translator::Gettext->new; print __"Hello World\n"; # language determined by environment # internal use my $msg = Log::Report::Message->new( _msgid => "Hello World\n", _textdomain => 'my-domain', ); print Log::Report::Translator::Gettext->new ->translate($msg, 'nl-BE'); =head1 DESCRIPTION UNTESTED!!! PLEASE CONTRIBUTE!!! Translate a message using the GNU gettext infrastructure. Guido Flohr reports: be aware that Locale::gettext is only a binding for the C library libintl and depends on its features. That means that your module will effectively only run on GNU systems and maybe on Solaris (depending on the exact version), because only these systems provide the plural handling functions ngettext(), dngettext() and dcngettext(). Sooner or later you will probably also need bind_textdomain_codeset() which is also only available on certain systems. Extends L<"DESCRIPTION" in Log::Report::Translator|Log::Report::Translator/"DESCRIPTION">. =head1 METHODS Extends L<"METHODS" in Log::Report::Translator|Log::Report::Translator/"METHODS">. =head2 Constructors Extends L<"Constructors" in Log::Report::Translator|Log::Report::Translator/"Constructors">. =over 4 =item $class-EB(%options) Inherited, see L =back =head2 Accessors Extends L<"Accessors" in Log::Report::Translator|Log::Report::Translator/"Accessors">. =head2 Translating Extends L<"Translating" in Log::Report::Translator|Log::Report::Translator/"Translating">. =over 4 =item $obj-EB($domain, $locale) Inherited, see L =item $obj-EB($msg, $lang, $ctxt) Inherited, see L =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Translator/Gettext.pm0000644000175000001440000000270115103071403024416 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Translator::Gettext;{ our $VERSION = '1.15'; } use base 'Log::Report::Translator'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use Locale::gettext; #-------------------- sub translate($;$$) { my ($msg, $lang, $ctxt) = @_; #XXX MO: how to use $lang when specified? my $domain = $msg->{_textdomain}; load_domain $domain; my $count = $msg->{_count}; defined $count ? ( defined $msg->{_category} ? dcngettext($domain, $msg->{_msgid}, $msg->{_plural}, $count, $msg->{_category}) : dngettext($domain, $msg->{_msgid}, $msg->{_plural}, $count) ) : ( defined $msg->{_category} ? dcgettext($domain, $msg->{_msgid}, $msg->{_category}) : dgettext($domain, $msg->{_msgid}) ); } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Translator/POT.pm0000644000175000001440000000756315103071403023447 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! #oorestyle: old style disclaimer to be removed. # This code is part of distribution Log-Report-Lexicon. Meta-POD processed # with OODoc into POD and HTML manual-pages. See README.md # Copyright Mark Overmeer. Licensed under the same terms as Perl itself. package Log::Report::Translator::POT;{ our $VERSION = '1.15'; } use base 'Log::Report::Translator'; use warnings; use strict; use Log::Report 'log-report-lexicon'; use Log::Report::Lexicon::Index; use Log::Report::Lexicon::POTcompact; use POSIX qw/:locale_h/; use Scalar::Util qw/blessed/; use File::Spec (); my %lexicons; sub _fn_to_lexdir($); # Work-around for missing LC_MESSAGES on old Perls and Windows { no warnings; eval "&LC_MESSAGES"; *LC_MESSAGES = sub(){5} if $@; } #-------------------- sub new(@) { my $class = shift; # Caller cannot wait until init() $class->SUPER::new(callerfn => (caller)[1], @_); } sub init($) { my ($self, $args) = @_; $self->SUPER::init($args); my $lex = delete $args->{lexicons} || delete $args->{lexicon} || (ref $self eq __PACKAGE__ ? [] : _fn_to_lexdir $args->{callerfn}); +($Log::Report::Lexicon::Index::VERSION || 999) >= 1.00 or error __x"You have to upgrade Log::Report::Lexicon to at least 1.00"; my @lex; foreach my $dir (ref $lex eq 'ARRAY' ? @$lex : $lex) { # lexicon indexes are shared my $l = $lexicons{$dir} ||= Log::Report::Lexicon::Index->new($dir); $l->index; # index the files now push @lex, $l; } $self->{LRTP_lexicons} = \@lex; $self->{LRTP_charset} = $args->{charset}; $self; } sub _fn_to_lexdir($) { my $fn = shift; $fn =~ s/\.pm$//; File::Spec->catdir($fn, 'messages'); } #-------------------- sub lexicons() { @{ $_[0]->{LRTP_lexicons}} } sub charset() { $_[0]->{LRTP_charset} } #-------------------- sub translate($;$$) { my ($self, $msg, $lang, $ctxt) = @_; #!!! do not debug with $msg in a print: recursion my $domain = $msg->{_domain}; my $dname = blessed $domain ? $domain->name : $domain; my $locale = $lang || setlocale(LC_MESSAGES) or return $self->SUPER::translate($msg, $lang, $ctxt); my $pot = exists $self->{LRTP_pots}{$dname}{$locale} ? $self->{LRTP_pots}{$dname}{$locale} : $self->load($dname, $locale); ($pot ? $pot->msgstr($msg->{_msgid}, $msg->{_count}, $ctxt) : undef) || $self->SUPER::translate($msg, $lang, $ctxt); } sub load($$) { my ($self, $dname, $locale) = @_; foreach my $lex ($self->lexicons) { my $fn = $lex->find($dname, $locale); !$fn && $lex->list($dname) and last; # there are tables for dname, but not our lang $fn or next; my ($ext) = lc($fn) =~ m/\.(\w+)$/; my $class = $ext eq 'mo' ? 'Log::Report::Lexicon::MOTcompact' : $ext eq 'po' ? 'Log::Report::Lexicon::POTcompact' : error __x"unknown translation table extension '{ext}' in {filename}", ext => $ext, filename => $fn; info __x"read table {filename} as {class} for {dname} in {locale}", filename => $fn, class => $class, dname => $dname, locale => $locale if $dname ne 'log-report'; # avoid recursion eval "require $class" or panic $@; return $self->{LRTP_pots}{$dname}{$locale} = $class->read($fn, charset => $self->charset); } $self->{LRTP_pots}{$dname}{$locale} = undef; } 1; Log-Report-Lexicon-1.15/lib/Log/Report/Translator/Context.pm0000644000175000001440000000775015103071404024430 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Translator::Context;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; #-------------------- sub new(@) { my $class = shift; (bless {}, $class)->init({@_}) } sub init($) { my ($self, $args) = @_; $self->{LRTC_rules} = $self->_context_table($args->{rules} || {}); $self; } #-------------------- sub rules() { $_[0]->{LRTC_rules} } #-------------------- sub _strip_ctxt_spec($) { my $msgid = shift; my @tags; while($msgid =~ s/\{ ([^<}]*) \<(\w+) ([^}]*) \}/ length "$1$3" ? "{$1$3}" : ''/xe) { push @tags, $2; } ($msgid, [sort @tags]); } sub ctxtFor($$;$) { my ($self, $msg, $lang, $def_context) = @_; my $rawid = $msg->msgid; my ($msgid, $tags) = _strip_ctxt_spec $rawid; @$tags or return ($msgid, undef); my $maps = $self->rules; $lang =~ s/_.*//; my $msg_context = $self->needDecode($rawid, $msg->context || {}); $def_context ||= {}; #use Data::Dumper; #warn "context = ", Dumper $msg, $msg_context, $def_context; my @c; foreach my $tag (@$tags) { my $map = $maps->{$tag} or error __x"no context definition for `{tag}' in `{msgid}'", tag => $tag, msgid => $rawid; my $set = $map->{$lang} || $map->{default}; next if $set eq 'IGNORE'; my $v = $msg_context->{$tag} || $def_context->{$tag}; unless($v) { warning __x"no value for tag `{tag}' in the context", tag => $tag; ($v) = keys %$set; } unless($set->{$v}) { warning __x"unknown alternative `{alt}' for tag `{tag}' in context of `{msgid}'", alt => $v, tag => $tag, msgid => $rawid; ($v) = keys %$set; } push @c, "$tag=$set->{$v}"; } my $msgctxt = join ' ', sort @c; ($msgid, $msgctxt); } sub needDecode($@) { my ($thing, $source) = (shift, shift); return +{@_} if @_ > 1; my $c = shift; return $c if !defined $c || ref $c eq 'HASH'; my %c; foreach (ref $c eq 'ARRAY' ? @$c : (split /[\s,]+/, $c)) { my ($kw, $val) = split /\=/, $_, 2; defined $val or error __x"tags value must have form `a=b', found `{this}' in `{source}'", this => $_, source => $source; $c{$kw} = $val; } \%c; } sub expand($$@) { my ($self, $raw, $lang) = @_; my ($msgid, $tags) = _strip_ctxt_spec $raw; $lang =~ s/_.*//; my $maps = $self->rules; my @options = []; foreach my $tag (@$tags) { my $map = $maps->{$tag} or error __x"unknown context tag '{tag}' used in '{msgid}'", tag => $tag, msgid => $msgid; my $set = $map->{$lang} || $map->{default}; my %uniq = map +("$tag=$_" => 1), values %$set; my @oldopt = @options; @options = (); foreach my $alt (keys %uniq) { push @options, map +[ @$_, $alt ], @oldopt; } } ($msgid, [sort map join(' ', @$_), @options]); } sub _context_table($) { my ($self, $rules) = @_; my %rules; foreach my $tag (keys %$rules) { my $d = $rules->{$tag}; $d = +{ alternatives => $d } if ref $d eq 'ARRAY'; my %simple; my $default = $d->{default} || {}; # default map if(my $alt = $d->{alternatives}) # simpelest map { $default = +{ map +($_ => $_), @$alt }; } $simple{default} = $default; foreach my $set (keys %$d) { next if $set eq 'default' || $set eq 'alternatives'; my %set = (%$default, %{$d->{$set}}); $simple{$_} = \%set for split /\,/, $set; # table per lang } $rules{$tag} = \%simple; } \%rules; } #-------------------- 1; Log-Report-Lexicon-1.15/lib/Log/Report/Translator/Context.pod0000644000175000001440000003411115103071404024565 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Translator::Context - handle translation contexts =head1 SYNOPSIS # usually, the context information is in a separate file textdomain 'my-domain', config => $filename; =head1 DESCRIPTION [Added in L v1.00] 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 translated diffently in one file or the other. For instance, two libraries used in the same application, or two componentent within a single library both want to used 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 consequently 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. For L, the power of "context" is extended with selecting between alternatives for the use of a msgid B. 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 context keyword in the message: my ($name, $sex) = ('Jack', 'male'); print __x"{name $name, _context => "gender=$sex"; =head1 METHODS =head2 Constructors =over 4 =item $class-EB(%options) Z<> -Option--Default rules {} =over 2 =item rules => HASH =back =back =head2 Attributes =over 4 =item $obj-EB() Returns a HASH to the simplified context maps. =back =head2 Action =over 4 =item $obj-EB( $message, $lang, [$context] ) Returns a pair of the MSGID stripped from context markup, and the context evaluated into the msgctxt string. The C<$message> is a L object. The C<$context> is the default context for a certain textdomain. my ($msgid, $msgctxt) = $context->ctxtFor($msg, $lang, $context); =item $obj-EB($msgid, $language, %options) Expand the context settings into all possible combinations which need translations in the PO file. This may depend on the C<$language>. The C<$msgid> is used in error messages. =item $any-EB($source, STRING|ARRAY|HASH|PAIRS) Converts the context settings passed with the MSGID, into a C which will be matched to the context providers. =back =head1 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 translated diffently in one file or the other. For instance, two libraries used in the same application, or two componentent within a single library both want to used 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 consequently 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. =head2 Contexts in Log::Report For L, the power of "context" is extended with selecting between alternatives for the use of a msgid B. 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 context keyword in the message: my ($name, $sex) = ('Jack', 'male'); print __x"{name $name, _context => "gender=$sex"; This would also be possible in traditional gettext, although probably rarely used. A complication is that the scripts to maintain the po tables are not too smart; do not understand complex code constructs. Probably this would beed needed: if(sex==MALE) { printf pgettext('male', "%s found his key\n", name); } else { printf pgettext('female', "%s found her key\n", name); } =head2 Using context_rules In L's extended concept of "contexts", you can select between multiple translations for the same msgid, when they =over 4 =item * appear with different purpose (like gnu's concept of contexts) =item * need alternative translation sets B =item * interpolate global parameters in messages =back 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 is a much broader need for context sensitive translations, which is not in the provided by standard gettext: environmental information or parameters may influence the translation more than simply solvable 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 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 would need to translate C and C to the language as well. But in some languages, the differences between addressed genders have more impact on the whole sentence. So, L translations add extra syntax: my ($name, $gender) = ('Jack', 'male'); print __x"{name $name, _context => "gender=$gender"; The C marking tells the translation table builder (xgettext-perl) and the translation handler that there is a context active. 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 C script must share information to understand which genders are available. See the section on "Configuration" below. Another example: print __x"greetings{ '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) C permits you to set-up a context for a whole text-domain, which means that multiple context rules may be active at any moment. =head3 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. =head3 Specifying the context per Domain Above examples are to be specified per message. You may also set a default. The top of your modules set 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, the C<_context> attribute used by strings are overruling these. =head3 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. In all or none of the alternatives 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. B that most (all?) existing tools which smartly edit PO-files do not understand these constructs: they see the msgctxt as 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. =head3 Configuration The tools which handle translations expect the msgctxt to be static. For instance, contain a filename where the string is used to disambigue accidental collissions 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 L. Example of such configuration file: (JSON syntax and Perl syntax) === JSON === ==== Perl == = {{ "context_rules" : { context_rules => { "gender" : [ gender => [ "male", 'male', "female" 'female' ] ] } } } } or { { "context_rules" : { context_rules => { "gender" : { gender => { "alternatives" : [ alternatives => [ "male", 'male', "female", 'female', "unknown" 'unknown' ] ] ... more config for 'gender' ... } } } } } } As "alternatives", we list the alternatives as known by the application internals. Each msgid which contains a C<< {> mark will be replicated three times, in each language table. Each copy will be marked with a different value from "alternatives". However, languages differ. For instance, in some language we may address the C gender as being a male person. In other languages, the translation can express this "unknown" personality. To get this to work, you can use the C construct. The default C, as used in the previous example, is simply mapping the alternatives directly on msgctxt values which are the same: { { 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, there will only be two msgid copies in a language file, because at run-time the "unknown" is mapped on "male". An exception for the Dutch (nl*) and German (de*) tables, which apparently support the third gender. If you are not interested for a certain tag, then put it on 'IGNORE' as default or for your language. "default" : "IGNORE", default => 'IGNORE' "nl": "IGNORE" nl => 'IGNORE' =head1 DIAGNOSTICS =over 4 =item Error: no context definition for `$tag' in `$msgid' Cast by C =item Warning: no value for tag `$tag' in the context Cast by C =item Error: tags value must have form `a=b', found `$this' in `$source' Cast by C =item Warning: unknown alternative `$alt' for tag `$tag' in context of `$msgid' Cast by C =item Error: unknown context tag '$tag' used in '$msgid' Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Translator/POT.pod0000644000175000001440000000715415103071404023612 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Translator::POT - translation based on POT files =head1 INHERITANCE Log::Report::Translator::POT is a Log::Report::Translator =head1 SYNOPSIS # internal use my $msg = Log::Report::Message->new( _msgid => "Hello World\n", _domain => 'my-domain', ); print Log::Report::Translator::POT ->new(lexicons => $dir) ->translate($msg, 'nl-BE'); # normal use (end-users view in the program's ::main) textdomain 'my-domain', translator => Log::Report::Translator::POT->new(lexicon => $dir); print __"Hello World\n"; =head1 DESCRIPTION Translate a message by directly accessing POT files. The files will load lazily (unless forced). This module accesses the PO's in a compact way, using L, which is much more efficient than L. Extends L<"DESCRIPTION" in Log::Report::Translator|Log::Report::Translator/"DESCRIPTION">. =head1 METHODS Extends L<"METHODS" in Log::Report::Translator|Log::Report::Translator/"METHODS">. =head2 Constructors Extends L<"Constructors" in Log::Report::Translator|Log::Report::Translator/"Constructors">. =over 4 =item $class-EB(%options) Z<> -Option --Default charset > lexicons =over 2 =item charset => STRING Enforce character set for files. We default to reading the character-set as defined in the header of each PO file. =item lexicons => DIRECTORY The DIRECTORY where the translations can be found. See L for the expected structure of such DIRECTORY. The default is based on the location of the module which instantiates this translator. The filename of the module is stripped from its C<.pm> extension, and used as directory name. Within that directory, there must be a directory named C, which will be the root directory of a L. =back » example: default lexicon directory # file xxx/perl5.8.8/My/Module.pm use Log::Report 'my-domain', translator => Log::Report::Translator::POT->new; # lexicon now in xxx/perl5.8.8/My/Module/messages/ =back =head2 Accessors Extends L<"Accessors" in Log::Report::Translator|Log::Report::Translator/"Accessors">. =over 4 =item $obj-EB() Returns the default charset, which can be overrule by the locale. =item $obj-EB() Returns a list of L objects, where the translation files may be located. =back =head2 Translating Extends L<"Translating" in Log::Report::Translator|Log::Report::Translator/"Translating">. =over 4 =item $obj-EB($domain, $locale) Inherited, see L =item $obj-EB($msg, $lang, $context) Inherited, see L =back =head1 DIAGNOSTICS =over 4 =item Error: You have to upgrade Log::Report::Lexicon to at least 1.00 Cast by C =item Info: read table $filename as $class for $dname in $locale Cast by C =item Error: unknown translation table extension '$ext' in $filename Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Win32Locale.pod0000644000175000001440000000514415103071404023036 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Win32Locale - unix/windows locales =head1 INHERITANCE Log::Report::Win32Locale is an Exporter =head1 SYNOPSIS # Only usable on Windows print codepage_to_iso(0x0413); # nl-NL print iso_to_codepage('nl_NL'); # 1043 printf "%x", iso_to_codepage('nl_NL'); # 413 my $iso = iso_locale(ms_codepage_id()); my $iso = iso_locale; # same print charset_encoding; # cp1252 print ms_codepage_id; # 1043 print ms_install_codepage_id; # 1043 print ms_locale; # Dutch (Netherlands) =head1 DESCRIPTION Windows uses different locales to represent languages: codepages. Programs which are written with L however, will contain ISO encoded language names; this module translates between them. The algorithms in this module are based on Win32::Locale and Win32::Codepage. =head1 FUNCTIONS =over 4 =item B() Returns the encoding name (usable with module Encode) based on the current codepage. For example, C for iso-8859-1 (latin-1) or C for Shift-JIS Japanese. Returns C if the encoding cannot be identified. =item B($codepage) Translate windows C<$codepage> into ISO code. The C<$codepage> is numeric or a hex string like '0x0304'. =item B( [$codepage] ) Returns the ISO string for the Microsoft codepage locale. Might return C/C. By default, the actual codepage is used. =item B($iso) Returns the numeric value of the codepage. The C<$iso> may look like this: C. Then, first the C is looked-up. If that does not exist, C is tried. =item B() Returns the numeric language ID for the current codepage language. For example, the numeric value for C<0x0409> for C, and C<0x0411> for C. Returns C if the codepage cannot be identified. =item B() Returns the numeric language ID for the installed codepage language. This is like L, but refers to the codepage that was the default when Windows was first installed. =item B() Returns the locale setting from the control panel. =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Win32Locale.pm0000644000175000001440000003771215103071404022676 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Win32Locale;{ our $VERSION = '1.15'; } use base 'Exporter'; use warnings; use strict; use Log::Report 'log-report-lexicon'; our @EXPORT = qw/ codepage_to_iso iso_to_codepage iso_locale charset_encoding ms_codepage_id ms_install_codepage_id ms_locale /; use Win32::TieRegistry; my (%codepage2iso, %localewin2iso, %charsetwin); while() { my ($codepage, $iso, $localewin, $charsetwin, $name) = split /\,\s*/, $_, 5; defined $name or die "Missing field in '$_'"; $codepage2iso{hex $codepage} = $iso; $localewin2iso{$localewin} = $iso; $charsetwin{$localewin} = $charsetwin; } my %iso2codepage = reverse %codepage2iso; close DATA; #-------------------- sub codepage_to_iso($) { my $cp = shift; defined $cp ? $codepage2iso{$cp =~ m/^0x/i ? hex($cp) : $cp} : (); } sub iso_to_codepage($) { my $iso = shift; return $iso2codepage{$iso} if $iso2codepage{$iso}; my ($lang) = split $iso, /\_/; $iso2codepage{$lang}; } sub iso_locale(;$) { my $locale = shift; if(defined $locale) { my $iso = $localewin2iso{$locale} || $codepage2iso{$locale}; return $iso if $iso; } codepage_to_iso(ms_codepage_id()) || codepage_to_iso(ms_locale()); } # the following functions are rewrites of Win32::Codepage version 1.00 # Copyright 2005 Clotho Advanced Media, Inc. Under perl license. # Win32 does not nicely export the functions. my $nls = 'HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Nls'; my $del = +{ Access => Win32::TieRegistry::KEY_READ(), Delimiter => '/' }; my $codepages = Win32::TieRegistry->new("$nls/CodePage", $del); my $languages = Win32::TieRegistry->new("$nls/Language", $del); sub charset_encoding { my $charset = $codepages->GetValue("ACP") || $codepages->GetValue("OEMCP"); $charset && $charset =~ m/^[0-9a-fA-F]+$/ ? "cp".lc($charset) : undef; } sub ms_codepage_id { my $id = $languages->GetValue("Default"); $id && $id =~ m/^[0-9a-fA-F]+$/ ? hex($id) : undef; } sub ms_install_codepage_id { my $id = $languages->GetValue("InstallLanguage"); $id && $id =~ m/^[0-9a-fA-F]+$/ ? hex($id) : undef; } # the following functions are rewrites of Win32::Locale version 0.04 # Copyright (c) 2001,2003 Sean M. Burke, Under perl license. # The module seems unmaintained, and treating the 'region' in the ISO # code as lower-case is a mistake. my $i18n = Win32::TieRegistry->new("HKEY_CURRENT_USER/Control Panel/International", $del); sub ms_locale { my $locale = $i18n->GetValue("Locale"); $locale =~ m/^[0-9a-fA-F]+$/ ? hex($locale) : undef; } 1; # taken from http://www.microsoft.com/globaldev/nlsweb on 2007/10/22 # merged with http://docs.moodle.org/en/Table_of_locales # columns: codepage,ISO,localewin,localewincharset,language name # use a wide terminal and tabstop=8 # After changes, sort with :.,$!sort -t, -k2,2 __DATA__ 0x0036, af, , , Afrikaans 0x0436, af_ZA, Afrikaans_South Africa.1252, WINDOWS-1252, Afrikaans (South Africa) 0x045E, am_ET, , , Amharic (Ethiopia) 0x0001, ar, , , Arabic 0x3801, ar_AE, , , Arabic (U.A.E.) 0x3C01, ar_BH, , , Arabic (Bahrain) 0x1401, ar_DZ, , , Arabic (Algeria) 0x0C01, ar_EG, , , Arabic (Egypt) 0x0801, ar_IQ, , , Arabic (Iraq) 0x2C01, ar_JO, , , Arabic (Jordan) 0x3401, ar_KW, , , Arabic (Kuwait) 0x3001, ar_LB, , , Arabic (Lebanon) 0x1001, ar_LY, , , Arabic (Libya) 0x1801, ar_MA, , , Arabic (Morocco) 0x047A, arn_CL, , , Mapudungun (Chile) 0x2001, ar_OM, , , Arabic (Oman) 0x4001, ar_QA, , , Arabic (Qatar) 0x0401, ar_SA, Arabic_Saudi Arabia.1256, WINDOWS-1256, Arabic (Saudi Arabia) 0x2801, ar_SY, , , Arabic (Syria) 0x1C01, ar_TN, , , Arabic (Tunisia) 0x2401, ar_YE, , , Arabic (Yemen) 0x044D, as_IN, , , Assamese (India) 0x002C, az, , , Azeri 0x082C, az_Cyrl_AZ, , , Azeri (Cyrillic, Azerbaijan) 0x042C, az_Latn_AZ, , , Azeri (Latin, Azerbaijan) 0x046D, ba_RU, , , Bashkir (Russia) 0x0023, be, , , Belarusian 0x0423, be_BY, Belarusian_Belarus.1251, WINDOWS-1251, Belarusian (Belarus) 0x0002, bg, Bulgarian_Bulgaria.1251, WINDOWS-1251, Bulgarian 0x0402, bg_BG, , , Bulgarian (Bulgaria) 0x0845, bn_BD, , , Bengali (Bangladesh) 0x0445, bn_IN, Bengali (India), , Bengali (India) 0x0451, bo_CN, , , Tibetan (PRC) 0x047E, br_FR, , , Breton (France) 0x201A, bs_Cyrl_BA, , , Bosnian (Cyrillic, Bosnia and Herzegovina) 0x141A, bs_Latn_BA, Serbian (Latin), WINDOWS-1250, Bosnian (Latin, Bosnia and Herzegovina) 0x0003, ca, , , Catalan 0x0403, ca_ES, Catalan_Spain.1252, WINDOWS-1252, Catalan (Catalan) 0x0483, co_FR, , , Corsican (France) 0x0005, cs, , , Czech 0x0405, cs_CZ, Czech_Czech Republic.1250, WINDOWS-1250, Czech (Czech Republic) 0x0452, cy_GB, , , Welsh (United Kingdom) 0x0006, da, , , Danish 0x0406, da_DK, Danish_Denmark.1252, WINDOWS-1252, Danish (Denmark) 0x0007, de, , , German 0x0C07, de_AT, , , German (Austria) 0x0807, de_CH, , , German (Switzerland) 0x0407, de_DE, German_Germany.1252, WINDOWS-1252, German (Germany) 0x1407, de_LI, , , German (Liechtenstein) 0x1007, de_LU, , , German (Luxembourg) 0x0065, div, , , Divehi 0x0465, div_MV, , , Divehi (Maldives) 0x0008, el, , , Greek 0x0408, el_GR, Greek_Greece.1253, WINDOWS-1253, Greek (Greece) 0x0009, en, , , English 0x2409, en_029, , , English (Caribbean) 0x0C09, en_AU, English_Australia.1252, , English (Australia) 0x2809, en_BZ, , , English (Belize) 0x1009, en_CA, , , English (Canada) 0x0809, en_GB, , , English (United Kingdom) 0x1809, en_IE, , , English (Ireland) 0x4009, en_IN, , , English (India) 0x2009, en_JM, , , English (Jamaica) 0x4409, en_MY, , , English (Malaysia) 0x1409, en_NZ, , , English (New Zealand) 0x3409, en_PH, , , English (Republic of the Philippines) 0x4809, en_SG, , , English (Singapore) 0x2C09, en_TT, , , English (Trinidad and Tobago) 0x0409, en_US, , , English (United States) 0x1C09, en_ZA, , , English (South Africa) 0x3009, en_ZW, , , English (Zimbabwe) 0x000A, es, , , Spanish 0x2C0A, es_AR, , , Spanish (Argentina) 0x400A, es_BO, , , Spanish (Bolivia) 0x340A, es_CL, , , Spanish (Chile) 0x240A, es_CO, , , Spanish (Colombia) 0x140A, es_CR, , , Spanish (Costa Rica) 0x1C0A, es_DO, , , Spanish (Dominican Republic) 0x300A, es_EC, , , Spanish (Ecuador) 0x0C0A, es_ES, Spanish_Spain.1252, WINDOWS-1252, Spanish (Spain) 0x100A, es_GT, , , Spanish (Guatemala) 0x480A, es_HN, , , Spanish (Honduras) 0x080A, es_MX, , , Spanish (Mexico) 0x4C0A, es_NI, , , Spanish (Nicaragua) 0x180A, es_PA, , , Spanish (Panama) 0x280A, es_PE, , , Spanish (Peru) 0x500A, es_PR, , , Spanish (Puerto Rico) 0x3C0A, es_PY, , , Spanish (Paraguay) 0x440A, es_SV, , , Spanish (El Salvador) 0x540A, es_US, , , Spanish (United States) 0x380A, es_UY, , , Spanish (Uruguay) 0x200A, es_VE, , , Spanish (Venezuela) 0x0025, et, , , Estonian 0x0425, et_EE, Estonian_Estonia.1257, WINDOWS-1257, Estonian (Estonia) 0x002D, eu, , , Basque 0x042D, eu_ES, Basque_Spain.1252, WINDOWS-1252, Basque (Basque) 0x0029, fa, , , Persian 0x0429, fa_IR, , , Persian , fa_IR, Farsi_Iran.1256, WINDOWS-1256, Farsi (Iran) 0x000B, fi, , , Finnish 0x040B, fi_FI, Finnish_Finland.1252, WINDOWS-1252, Finnish (Finland) 0x0464, fil_PH, Filipino_Philippines.1252, WINDOWS-1252, Filipino (Philippines) 0x0038, fo, , , Faroese 0x0438, fo_FO, , , Faroese (Faroe Islands) 0x000C, fr, , , French 0x080C, fr_BE, , , French (Belgium) 0x0C0C, fr_CA, , , French (Canada) 0x100C, fr_CH, , , French (Switzerland) 0x040C, fr_FR, French_France.1252, WINDOWS-1252, French (France) 0x140C, fr_LU, , , French (Luxembourg) 0x180C, fr_MC, , , French (Principality of Monaco) 0x0462, fy_NL, , , Frisian (Netherlands) , ga, , WINDOWS-1252, Gaelic; Scottish Gaelic 0x083C, ga_IE, , , Irish (Ireland) 0x0056, gl, , , Galician 0x0456, gl_ES, , , Galician (Galician) , gl_ES, Galician_Spain.1252, WINDOWS-1252, Gallego 0x0484, gsw_FR, , , Alsatian (France) 0x0047, gu, , , Gujarati 0x0447, gu_IN, Gujarati_India.0, , Gujarati (India) 0x0468, ha_Latn_NG, , , Hausa (Latin, Nigeria) 0x000D, he, , , Hebrew 0x040D, he_IL, Hebrew_Israel.1255, WINDOWS-1255, Hebrew (Israel) 0x0039, hi, Hindi.65001, , Hindi 0x0439, hi_IN, , , Hindi (India) 0x001A, hr, , , Croatian 0x101A, hr_BA, , , Croatian (Latin, Bosnia and Herzegovina) 0x041A, hr_HR, Croatian_Croatia.1250, WINDOWS-1250, Croatian (Croatia) 0x000E, hu, , , Hungarian 0x040E, hu_HU, Hungarian_Hungary.1250, WINDOWS-1250, Hungarian (Hungary) 0x002B, hy, , , Armenian 0x042B, hy_AM, , , Armenian (Armenia) 0x0021, id, , , Indonesian 0x0421, id_ID, Indonesian_indonesia.1252, WINDOWS-1252, Indonesian (Indonesia) 0x0470, ig_NG, , , Igbo (Nigeria) 0x0478, ii_CN, , , Yi (PRC) 0x000F, is, , , Icelandic 0x040F, is_IS, Icelandic_Iceland.1252, WINDOWS-1252, Icelandic (Iceland) 0x0010, it, , , Italian 0x0810, it_CH, , , Italian (Switzerland) 0x0410, it_IT, Italian_Italy.1252, WINDOWS-1252, Italian (Italy) 0x045D, iu_Cans_CA, , , Inuktitut (Syllabics, Canada) 0x085D, iu_Latn_CA, , , Inuktitut (Latin, Canada) 0x0011, ja, , , Japanese 0x0411, ja_JP, Japanese_Japan.932, CP932, Japanese (Japan) 0x0037, ka, , , Georgian 0x0437, ka_GE, , , Georgian (Georgia) , ka_GE, Georgian_Georgia.65001, , Georgian 0x003F, kk, , , Kazakh 0x043F, kk_KZ, , , Kazakh (Kazakhstan) 0x046F, kl_GL, , , Greenlandic (Greenland) , km, Khmer.65001, , Khmer 0x0453, km_KH, , , Khmer (Cambodia) 0x004B, kn, , , Kannada 0x044B, kn_IN, kn_IN.UTF-8, Kannada.65001, Kannada (India) 0x0012, ko, , , Korean 0x0057, kok, , , Konkani 0x0457, kok_IN, , , Konkani (India) 0x0412, ko_KR, Korean_Korea.949, EUC-KR, Korean (Korea) 0x0040, ky, , , Kyrgyz 0x0440, ky_KG, , , Kyrgyz (Kyrgyzstan) 0x046E, lb_LU, , , Luxembourgish (Luxembourg) 0x0454, lo_LA, Lao_Laos.UTF-8, WINDOWS-1257, Lao (Lao P.D.R.) 0x0027, lt, , , Lithuanian 0x0427, lt_LT, Lithuanian_Lithuania.1257, WINDOWS-1257, Lithuanian (Lithuania) 0x0026, lv, , , Latvian 0x0426, lv_LV, Latvian_Latvia.1257, WINDOWS-1257, Latvian (Latvia) 0x0481, mi_NZ, Maori.1252, WINDOWS-1252, Maori (New Zealand) 0x002F, mk, , , Macedonian 0x042F, mk_MK, , , Macedonian (Former Yugoslav Republic of Macedonia) 0x044C, ml_IN, Malayalam_India.x-iscii-ma, x-iscii-ma, Malayalam (India) 0x0050, mn, , , Mongolian 0x0450, mn_MN, Cyrillic_Mongolian.1251, , Mongolian (Cyrillic, Mongolia) 0x0850, mn_Mong_CN, , , Mongolian (Traditional Mongolian, PRC) 0x047C, moh_CA, , , Mohawk (Mohawk) 0x004E, mr, , , Marathi 0x044E, mr_IN, , , Marathi (India) 0x003E, ms, , , Malay 0x083E, ms_BN, , , Malay (Brunei Darussalam) 0x043E, ms_MY, , , Malay (Malaysia) 0x043A, mt_MT, , , Maltese (Malta) 0x0461, ne_NP, , , Nepali (Nepal) 0x0013, nl, , , Dutch 0x0813, nl_BE, , , Dutch (Belgium) 0x0413, nl_NL, Dutch_Netherlands.1252, WINDOWS-1252, Dutch (Netherlands) 0x0814, nn_NO, Norwegian-Nynorsk_Norway.1252, WINDOWS-1252, Norwegian, Nynorsk (Norway) 0x0014, no, , , Norwegian 0x0414, no_NO, Norwegian_Norway.1252, WINDOWS-1252, Norwegian, Bokmål (Norway) 0x046C, nso_ZA, , , Sesotho sa Leboa (South Africa) 0x0482, oc_FR, , , Occitan (France) 0x0448, or_IN, , , Oriya (India) 0x0046, pa, , , Punjabi 0x0446, pa_IN, , , Punjabi (India) 0x0015, pl, , , Polish 0x0415, pl_PL, Polish_Poland.1250, WINDOWS-1250, Polish (Poland) 0x048C, prs_AF, , , Dari (Afghanistan) 0x0463, ps_AF, , , Pashto (Afghanistan) 0x0016, pt, , , Portuguese 0x0416, pt_BR, Portuguese_Brazil.1252, WINDOWS-1252, Portuguese (Brazil) 0x0816, pt_PT, Portuguese_Portugal.1252, WINDOWS-1252, Portuguese (Portugal) 0x0486, qut_GT, , , K'iche (Guatemala) 0x046B, quz_BO, , , Quechua (Bolivia) 0x086B, quz_EC, , , Quechua (Ecuador) 0x0C6B, quz_PE, , , Quechua (Peru) 0x0417, rm_CH, , , Romansh (Switzerland) 0x0018, ro, , , Romanian 0x0418, ro_RO, Romanian_Romania.1250, WINDOWS-1250, Romanian (Romania) 0x0019, ru, , , Russian 0x0419, ru_RU, Russian_Russia.1251, WINDOWS-1251, Russian (Russia) 0x0487, rw_RW, , , Kinyarwanda (Rwanda) 0x004F, sa, , , Sanskrit 0x0485, sah_RU, , , Yakut (Russia) 0x044F, sa_IN, , , Sanskrit (India) 0x0C3B, se_FI, , , Sami, Northern (Finland) 0x043B, se_NO, , , Sami, Northern (Norway) 0x083B, se_SE, , , Sami, Northern (Sweden) 0x045B, si_LK, , , Sinhala (Sri Lanka) 0x001B, sk, , , Slovak 0x041B, sk_SK, Slovak_Slovakia.1250, WINDOWS-1250, Slovak (Slovakia) 0x0024, sl, , , Slovenian 0x0424, sl_SI, Slovenian_Slovenia.1250, WINDOWS-1250, Slovenian (Slovenia) 0x183B, sma_NO, , , Sami, Southern (Norway) 0x1C3B, sma_SE, , , Sami, Southern (Sweden) 0x103B, smj_NO, , , Sami, Lule (Norway) 0x143B, smj_SE, , , Sami, Lule (Sweden) 0x243B, smn_FI, , , Sami, Inari (Finland) 0x203B, sms_FI, , , Sami, Skolt (Finland) , so_SO, , , Somali (Somalia) 0x001C, sq, , , Albanian 0x041C, sq_AL, Albanian_Albania.1250, WINDOWS-1250, Albanian (Albania) 0x7C1A, sr, , , Serbian 0x1C1A, sr_Cyrl_BA,Serbian (Cyrillic)_Serbia and Montenegro.1251,WINDOWS-1251,Serbian (Cyrillic, Bosnia and Herzegovina) 0x0C1A, sr_Cyrl_SP, , , Serbian (Cyrillic, Serbia) 0x181A, sr_Latn_BA, , , Serbian (Latin, Bosnia and Herzegovina) 0x081A, sr_Latn_SP, , , Serbian (Latin, Serbia) 0x001D, sv, , , Swedish 0x081D, sv_FI, , , Swedish (Finland) 0x041D, sv_SE, Swedish_Sweden.1252, WINDOWS-1252, Swedish (Sweden) 0x0041, sw, , , Kiswahili 0x0441, sw_KE, , , Kiswahili (Kenya) 0x005A, syr, , , Syriac 0x045A, syr_SY, , , Syriac (Syria) 0x0049, ta, , , Tamil 0x0449, ta_IN, , , Tamil (India) 0x004A, te, , , Telugu 0x044A, te_IN, , , Telugu (India) 0x0428, tg_Cyrl_TJ, , , Tajik (Cyrillic, Tajikistan) 0x001E, th, , , Thai 0x041E, th_TH, Thai_Thailand.874, WINDOWS-874, Thai (Thailand) 0x0442, tk_TM, , , Turkmen (Turkmenistan) 0x085F, tmz_Latn_DZ, , , Tamazight (Latin, Algeria) 0x0432, tn_ZA, , , Setswana (South Africa) 0x001F, tr, , , Turkish 0x041F, tr_TR, Turkish_Turkey.1254, WINDOWS-1254, Turkish (Turkey) 0x0044, tt, , , Tatar 0x0444, tt_RU, , , Tatar (Russia) 0x0480, ug_CN, , , Uighur (PRC) 0x0022, uk, , , Ukrainian 0x0422, uk_UA, Ukrainian_Ukraine.1251, WINDOWS-1251, Ukrainian (Ukraine) 0x0020, ur, , , Urdu 0x0420, ur_PK, , , Urdu (Islamic Republic of Pakistan) 0x0043, uz, , , Uzbek 0x0843, uz_Cyrl_UZ, , , Uzbek (Cyrillic, Uzbekistan) 0x0443, uz_Latn_UZ, , , Uzbek (Latin, Uzbekistan) 0x002A, vi, , , Vietnamese 0x042A, vi_VN, Vietnamese_Viet Nam.1258, WINDOWS-1258, Vietnamese (Vietnam) 0x082E, wee_DE, , , Lower Sorbian (Germany) 0x042E, wen_DE, , , Upper Sorbian (Germany) 0x0488, wo_SN, , , Wolof (Senegal) 0x0434, xh_ZA, , , isiXhosa (South Africa) 0x046A, yo_NG, , , Yoruba (Nigeria) 0x0804, zh_CN, Chinese_China.936, CP936, Chinese (People's Republic of China) 0x0004, zh_Hans,, , Chinese (Simplified) 0x7C04, zh_Hant,, , Chinese (Traditional) 0x0C04, zh_HK, , , Chinese (Hong Kong S.A.R.) 0x1404, zh_MO, , , Chinese (Macao S.A.R.) 0x1004, zh_SG, , , Chinese (Singapore) 0x0404, zh_TW, Chinese_Taiwan.950, CP950, Chinese (Taiwan) 0x0435, zu_ZA, , , siZulu (South Africa) Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon.pod0000644000175000001440000000360015103071404022410 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Lexicon - translation component of Log::Report =head1 SYNOPSIS =head1 DESCRIPTION This module is the main extry point for the distribution, but has currently no further use. This distribution contains all components of L which handle translations. If you do not need translations, you do not need to install this module. When you use L and need to add translations, it may be very little work: when you nicely wrote texts in the advised message format like print __x"Greetings to you, {name}", name => $name; fault __x"cannot open file {filename}", filename => $fn; then all is in perfect condition to introduce translations: it requires very little to no additions to the existing code! In this distribution: =over 4 =item * L Logic used by the F binary (also included here) to extract msgid's from perl scripts and (website) templates. =item * L Translation table administration, in PO or MO format. =item * L Translation table file file administration, understanding locales, domains, and attributes in the filenames. =item * L The run-time component of translations. =back =head1 METHODS =head2 Constructors =over 4 =item $class-EB(%options) Z<> =back =head2 Accessors =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/Lexicon.pm0000644000175000001440000000177115103071403022250 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Lexicon;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; #-------------------- sub new(@) { my $class = shift; (bless {}, $class)->init( +{ @_ } ); } sub init($) { shift } # $self, $args #-------------------- 1; Log-Report-Lexicon-1.15/lib/Log/Report/Extract.pod0000644000175000001440000000744715103071404022436 0ustar00markovusers00000000000000=encoding utf8 =head1 NAME Log::Report::Extract - Collect translatable strings =head1 INHERITANCE Log::Report::Extract is extended by Log::Report::Extract::PerlPPI Log::Report::Template::Extract =head1 SYNOPSIS # See the extensions =head1 DESCRIPTION This module helps maintaining the POT files, updating the list of message-ids which are kept in them. After initiation, the L method needs to be called with all files which changed since last processing and the existing PO files will get updated accordingly. If no translations exist yet, one C file will be created. =head1 METHODS =head2 Constructors =over 4 =item $class-EB(%options) Z<> -Option --Default charset 'utf-8' lexicon =over 2 =item charset => STRING The character-set used in the PO files. =item lexicon => DIRECTORY The place where the lexicon is kept. When no lexicon is defined yet, this will be the directory where an C file will be created. =back =back =head2 Accessors =over 4 =item $obj-EB($domain, $pot, %options) Z<> =item $obj-EB() Returns the character-set used inside the POT files. =item $obj-EB() Returns a sorted list of all known domain names. =item $obj-EB() Returns the L object, which is listing the files in the lexicon directory tree. =item $obj-EB($domain) Returns the list of L objects which contain the tables for C<$domain>. =back =head2 Processors =over 4 =item $obj-EB(%options) Remove all references. -Option--Default keep [] =over 2 =item keep => HASH|ARRAY Keep the information about these filename, either specified as ARRAY of names, or a HASH where the keys are the named. =back =item $obj-EB($filename, %options) Update the domains mentioned in the C<$filename>. All text-domains defined in the file will get updated automatically, but should not written before all files are processed. Returned is the number of messages found in this particular file. =item $obj-EB( [$domains] ) Show a status about the DOMAIN (by default all domains). At least mode verbose is required to see this. The statistics are sent to (L) dispatchers which accept notice and info. This could be syslog. When you have no explicit dispatchers in your program, the level of detail get controlled by the 'mode': use Log::Report mode => 'DEBUG'; # or 'VERBOSE' =item $obj-EB( $domain, $filename, $linenr, $context, $msg, [$msg_plural] ) Register the existence of a (C<$msg>, C<$msg_plural>) in all POTs of the C<$domain>. =item $obj-EB( [$domain], %options ) Update the information of the files related to C<$domain>, by default all processed DOMAINS. All information known about the written C<$domain> is removed from the cache. The C<%options> are passed to the C of the specific lexicon manager. =back =head1 DIAGNOSTICS =over 4 =item Fault: cannot create lexicon directory $dir: $! Cast by C =item Error: extractions require an explicit lexicon directory Cast by C =item Error: no context tags allowed in plural `$msgid' Cast by C =item Info: starting new textdomain $domain, template in $filename Cast by C =back =head1 SEE ALSO This module is part of Log-Report-Lexicon version 1.15, built on November 06, 2025. Website: F =head1 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. Log-Report-Lexicon-1.15/lib/Log/Report/messages/0000755000175000001440000000000015103071406022115 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/messages/log-report-lexicon/0000755000175000001440000000000015103071406025646 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/lib/Log/Report/messages/log-report-lexicon/nl_NL.po0000644000175000001440000002417615103070401027214 0ustar00markovusers00000000000000#. Header generated with Log::Report::Lexicon::POT 0.0 msgid "" msgstr "" "Project-Id-Version: log-report 0.01\n" "Report-Msgid-Bugs-To:\n" "POT-Creation-Date: 2007-05-14 17:14+0200\n" "PO-Revision-Date: 2025-11-06 10:53+0100\n" "Last-Translator: Mark Overmeer \n" "Language-Team:\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" #: lib/Log/Report/Translator/POT.pm:110 #, fuzzy msgid "You have to upgrade Log::Report::Lexicon to at least 1.00" msgstr "" #: lib/Log/Report/Extract.pm:58 msgid "cannot create lexicon directory {dir}" msgstr "kan lexicon map {dir} niet aanmaken" #: bin/xgettext-perl:63 #, fuzzy msgid "cannot create output directory {dir}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:177 lib/Log/Report/Lexicon/POT.pm:192 #: lib/Log/Report/Lexicon/POTcompact.pm:96 #, fuzzy msgid "cannot detect charset in {fn}" msgstr "" #: bin/xgettext-perl:75 #, fuzzy msgid "cannot read filename list from {fn}" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:175 lib/Log/Report/Lexicon/POTcompact.pm:82 #, fuzzy msgid "cannot read from file {fn} (unknown charset)" msgstr "" #: lib/Log/Report/Lexicon/POTcompact.pm:78 #, fuzzy msgid "cannot read in {charset} from file {fn}" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:171 msgid "cannot read in {cs} from file {fn}" msgstr "kan bestand {fn} niet lezen in {cs}" #: lib/Log/Report/Lexicon/MOTcompact.pm:107 #, fuzzy msgid "cannot read magic from {fn}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:99 #, fuzzy msgid "cannot read mo from file {fn}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:154 #, fuzzy msgid "cannot read msgids from {fn}, need {size} at {loc}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:129 #, fuzzy msgid "cannot read originals from {fn}, need {size} at {loc}" msgstr "" #: lib/Log/Report/Extract/PerlPPI.pm:142 #, fuzzy msgid "cannot read perl from file {filename}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:116 #, fuzzy msgid "cannot read superblock from {fn}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:138 #: lib/Log/Report/Lexicon/MOTcompact.pm:162 #, fuzzy msgid "cannot read translations from {fn}, need {size} at {loc}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:149 #, fuzzy msgid "cannot seek to {loc} in {fn} for msgid strings" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:126 #, fuzzy msgid "cannot seek to {loc} in {fn} for originals" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:158 #, fuzzy msgid "cannot seek to {loc} in {fn} for transl strings" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:135 #, fuzzy msgid "cannot seek to {loc} in {fn} for translations" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:253 #, fuzzy msgid "cannot write to file {fn} with {layers}" msgstr "kan bestand {fn} niet schrijven in {layers}" #: lib/Log/Report/Extract/PerlPPI.pm:290 #, fuzzy msgid "count missing in {function} in line {line}" msgstr "" #: bin/xgettext-perl:68 #, fuzzy msgid "do not combine command-line filenames with --files-from" msgstr "" #: lib/Log/Report/Extract/PerlPPI.pm:265 msgid "do not interpolate in msgid (found '{var}' in line {line})" msgstr "gebruik geen variabelen in een msgid (vond '{var}' op regel {line'})" #: lib/Log/Report/Lexicon/PO.pm:414 msgid "do not understand command '{cmd}' at {where}" msgstr "commando '{cmd}' op plaats {where} niet begrepen" #: lib/Log/Report/Lexicon/PO.pm:429 msgid "" "do not understand line at {where}:\n" " {line}" msgstr "" "de regel op {where} wordt niet begrepen:\n" " {line}" #: bin/xgettext-perl:60 #, fuzzy msgid "explicit output directory (-p) required" msgstr "" #: lib/Log/Report/Extract.pm:55 msgid "extractions require an explicit lexicon directory" msgstr "een expliciete lexicon directory is nodig voor de uittreksels" #: lib/Log/Report/Lexicon/MOTcompact.pm:192 lib/Log/Report/Lexicon/POT.pm:206 #: lib/Log/Report/Lexicon/POTcompact.pm:142 msgid "failed reading from file {fn}" msgstr "lezen uit bestand {fn} mislukt" #: lib/Log/Report/Extract.pm:235 msgid "found one pot file for domain {domain}" msgid_plural "found {_count} pot files for domain {domain}" msgstr[0] "één pot bestand voor domein {domain} gevonden" msgstr[1] "{_count} pot bestanden voor domain {domain} gevonden" #: lib/Log/Report/Lexicon/POTcompact.pm:93 #, fuzzy msgid "header not found for charset in {fn}" msgstr "" #: lib/Log/Report/Lexicon/Table.pm:127 msgid "invalid plural-form algorithm '{alg}'" msgstr "incorrect meervoudsvorm algoritme '{alg}'" #: lib/Log/Report/Extract/PerlPPI.pm:279 msgid "new-line is added automatically (found in line {line})" msgstr "een regel-overgang wordt automatisch toegevoegd (gevonden op regel {line})" #: lib/Log/Report/Extract/PerlPPI.pm:146 #, fuzzy msgid "no Perl in file {filename}" msgstr "" #: lib/Log/Report/Translator/Context.pm:123 #, fuzzy msgid "no context definition for `{tag}' in `{msgid}'" msgstr "" #: lib/Log/Report/Extract.pm:274 #, fuzzy msgid "no context tags allowed in plural `{msgid}'" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:243 msgid "no filename or file-handle specified for PO" msgstr "geen bestandsnaam of -handle meegegeven voor PO" #: lib/Log/Report/Lexicon/POT.pm:398 msgid "no header defined in POT for file {fn}" msgstr "geen kop opgegeven in POT in bestand {fn}" #: lib/Log/Report/Lexicon/PO.pm:88 #, fuzzy msgid "no msgid defined for PO" msgstr "" #: lib/Log/Report/Lexicon/PO.pm:434 msgid "no msgid in block {where}" msgstr "geen msgid in blok {where}" #: lib/Log/Report/Lexicon/PO.pm:513 msgid "no plurals for '{msgid}'" msgstr "geen meervoudsvormen voor '{msgid}'" #: lib/Log/Report/Extract/PerlPPI.pm:219 msgid "no text-domain for translatable at {fn} line {line}" msgstr "geen text-domain voor vertaalbare string in {fn} regel {line}" #: lib/Log/Report/Translator/Context.pm:130 #, fuzzy msgid "no value for tag `{tag}' in the context" msgstr "" #: lib/Log/Report/Extract/PerlPPI.pm:150 msgid "processing file {fn} in {charset}" msgstr "verwerk bestand {fn} in {charset}" #: bin/xgettext-perl:57 #, fuzzy msgid "programming language {lang} not supported" msgstr "" #: lib/Log/Report/Lexicon/PO.pm:425 msgid "quoted line is not a continuation at {where}" msgstr "regel met quotes is geen voortzetting in {where}" #: lib/Log/Report/Translator/POT.pm:190 #, fuzzy msgid "read table {filename} as {class} for {dname} in {locale}" msgstr "" #: bin/xgettext-perl:111 #, fuzzy msgid "skipping (not a template) {fn}" msgstr "" #: bin/xgettext-perl:132 #, fuzzy msgid "skipping (not perl) {fn}" msgstr "" #: bin/xgettext-perl:129 #, fuzzy msgid "skipping missing file {fn}" msgstr "" #: bin/xgettext-perl:98 #, fuzzy msgid "specify a text-domain (-d) for the templates" msgstr "" #: lib/Log/Report/Extract.pm:242 msgid "starting new textdomain {domain}, template in {filename}" msgstr "begin van nieuw textdomain {domain}, sjabloon in {filename}" #: lib/Log/Report/Lexicon/POTcompact.pm:208 msgid "string '{text}' not between quotes at {location}" msgstr "tekst '{text}' niet tussen quotes in {location}" #: lib/Log/Report/Extract/PerlPPI.pm:269 msgid "string is incorrect at line {line}: {error}" msgstr "foutieve string in regel {regel}: {error}" #: lib/Log/Report/Translator/Context.pm:163 #, fuzzy msgid "tags value must have form `a=b', found `{this}' in `{source}'" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:126 msgid "textdomain parameter is required" msgstr "tekstdomain argument is verplicht" #: lib/Log/Report/Lexicon/MOTcompact.pm:174 #, fuzzy msgid "the header is not the first entry, needed for charset in {fn}" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:376 msgid "the only acceptable parameter is 'ACTIVE', not '{p}'" msgstr "het enige geaccepteerde argument is 'ACTIVE', niet '{p}'" #: lib/Log/Report/Lexicon/Table.pm:103 #, fuzzy msgid "there is no Plural-Forms field in the header, but needed" msgstr "" #: lib/Log/Report/Lexicon/PO.pm:503 msgid "too many plurals for '{msgid}'" msgstr "te veel meervouden voor '{msgid}'" #: lib/Log/Report/Lexicon/POT.pm:358 #, fuzzy msgid "translation already exists for '{msgid}' with '{ctxt}" msgstr "" #: lib/Log/Report/Translator/Context.pm:134 #, fuzzy msgid "unknown alternative `{alt}' for tag `{tag}' in context of `{msgid}'" msgstr "" #: lib/Log/Report/Lexicon/PO.pm:389 msgid "unknown comment type '{cmd}' at {where}" msgstr "onbekend commentaar type '{cmd}' in {where}" #: lib/Log/Report/Translator/Context.pm:188 #, fuzzy msgid "unknown context tag '{tag}' used in '{msgid}'" msgstr "" #: lib/Log/Report/Lexicon/PO.pm:349 msgid "unknown flag {flag} ignored" msgstr "onbekende vlag {flag} wordt genegeerd" #: lib/Log/Report/Translator/POT.pm:188 #, fuzzy msgid "unknown translation table extension '{ext}' in {filename}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:182 lib/Log/Report/Lexicon/POT.pm:198 #: lib/Log/Report/Lexicon/POTcompact.pm:99 #, fuzzy msgid "unsupported charset {charset} in {fn}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:86 #, fuzzy msgid "unsupported explicit charset {charset} for {fn}" msgstr "" #: lib/Log/Report/Lexicon/MOTcompact.pm:112 #, fuzzy msgid "unsupported file type (magic number is {magic%x})" msgstr "" #: lib/Log/Report/Extract/PerlPPI.pm:197 #, fuzzy msgid "use double quotes not single, in {string} on {file} line {line}" msgstr "" #: lib/Log/Report/Lexicon/POT.pm:273 msgid "write errors for file {fn}" msgstr "schrijfproblemen bij bestand {fn}" #: lib/Log/Report/Extract.pm:183 msgid "{domain}: one file with {ids} msgids" msgid_plural "{domain}: {_count} files with each {ids} msgids" msgstr[0] "{domain}: één bestand met {ids} mgsids" msgstr[1] "{domain}: {_count} bestanden met elk {ids} msgids" #: lib/Log/Report/Extract.pm:178 msgid "{domain}: one file with {ids} msgids, {f} fuzzy and {i} inactive translations" msgid_plural "{domain}: {_count} files each {ids} msgids, {f} fuzzy and {i} inactive translations in total" msgstr[0] "{domain}: één bestand met {ids} mgsids, {f} fuzzy en {i} op non-actief" msgstr[1] "{domain}: {_count} bestanden met elk {ids} msgids, {f} fuzzy en {i} op non-actief in het totaal" #: lib/Log/Report/Extract.pm:170 msgid "{domain}: {fuzzy%3d} fuzzy, {inact%3d} inactive in {filename}" msgstr "{domain}: {fuzzy%3d} fuzzy, {inact%3d} op non-actief in {filename}" Log-Report-Lexicon-1.15/lib/Log/Report/Extract.pm0000644000175000001440000001312515103071403022255 0ustar00markovusers00000000000000# This code is part of Perl distribution Log-Report-Lexicon version 1.15. # The POD got stripped from this file by OODoc version 3.05. # 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. # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION *** #oodist: This file contains OODoc-style documentation which will get stripped #oodist: during its release in the distribution. You can use this file for #oodist: testing, however the code of this development version may be broken! package Log::Report::Extract;{ our $VERSION = '1.15'; } use warnings; use strict; use Log::Report 'log-report-lexicon'; use Log::Report::Lexicon::Index (); use Log::Report::Lexicon::POT (); #-------------------- sub new(@) { my $class = shift; (bless {}, $class)->init( {@_} ); } sub init($) { my ($self, $args) = @_; my $lexi = $args->{lexicon} || $args->{lexicons} or error __"extractions require an explicit lexicon directory"; -d $lexi or mkdir $lexi or fault __x"cannot create lexicon directory {dir}", dir => $lexi; $self->{LRE_index} = Log::Report::Lexicon::Index->new($lexi); $self->{LRE_charset} = $args->{LRE_charset} || 'utf-8'; $self->{LRE_domains} = {}; $self; } #-------------------- sub index() { $_[0]->{LRE_index} } sub charset() { $_[0]->{LRE_charset} } sub domains() {sort keys %{ $_[0]->{LRE_domains}} } sub pots($) { my ($self, $domain) = @_; my $r = $self->{LRE_domains}{$domain}; $r ? @$r : (); } sub addPot($$%) { my ($self, $domain, $pot) = @_; push @{$self->{LRE_domains}{$domain}}, ref $pot eq 'ARRAY' ? @$pot : $pot if $pot; } #-------------------- sub process($@) { my ($self, $fn, %opts) = @_; panic "not implemented"; } sub cleanup(%) { my ($self, %args) = @_; my $keep = $args{keep} || {}; $keep = +{ map +($_ => 1), @$keep } if ref $keep eq 'ARRAY'; foreach my $domain ($self->domains) { $_->keepReferencesTo($keep) for $self->pots($domain); } } sub showStats(;$) { my $self = shift; my @domains = @_ ? @_ : $self->domains; dispatcher needs => 'INFO' or return; foreach my $domain (@domains) { my $pots = $self->{LRE_domains}{$domain} or next; my ($msgids, $fuzzy, $inactive) = (0, 0, 0); foreach my $pot (@$pots) { my $stats = $pot->stats; next unless $stats->{fuzzy} || $stats->{inactive}; $msgids = $stats->{msgids}; next if $msgids == $stats->{fuzzy}; # ignore the template notice __x"{domain}: {fuzzy%3d} fuzzy, {inact%3d} inactive in {filename}", domain => $domain, fuzzy => $stats->{fuzzy}, inact => $stats->{inactive}, filename => $pot->filename; $fuzzy += $stats->{fuzzy}; $inactive += $stats->{inactive}; } if($fuzzy || $inactive) { info __xn"{domain}: one file with {ids} msgids, {f} fuzzy and {i} inactive translations", "{domain}: {_count} files each {ids} msgids, {f} fuzzy and {i} inactive translations in total", scalar(@$pots), domain => $domain, f => $fuzzy, ids => $msgids, i => $inactive; } else { info __xn"{domain}: one file with {ids} msgids", "{domain}: {_count} files with each {ids} msgids", scalar(@$pots), domain => $domain, ids => $msgids; } } } sub write(;$%) { my $self = shift; my ($domain, %args) = @_ % 2 ? @_ : (undef, @_); unless(defined $domain) # write all { $self->write($_) for $self->domains; return; } my $pots = delete $self->{LRE_domains}{$domain} or return; # nothing found for my $pot (@$pots) { $pot->updated; $pot->write(%args); } $self; } sub DESTROY() { $_[0]->write } sub _reset($$) { my ($self, $domain, $fn) = @_; my $pots = $self->{LRE_domains}{$domain} ||= $self->_read_pots($domain); $_->removeReferencesTo($fn) for @$pots; } sub _read_pots($) { my ($self, $domain) = @_; my $index = $self->index; my $charset = $self->charset; my @pots = map Log::Report::Lexicon::POT->read($_, charset=> $charset), $index->list($domain); trace __xn"found one pot file for domain {domain}", "found {_count} pot files for domain {domain}", @pots, domain => $domain; return \@pots if @pots; # new text-domain found, start template my $fn = $index->addFile("$domain.$charset.po"); info __x"starting new textdomain {domain}, template in {filename}", domain => $domain, filename => $fn; my $pot = Log::Report::Lexicon::POT->new( textdomain => $domain, filename => $fn, charset => $charset, version => 0.01 ); [ $pot ]; } sub store($$$$;$) { my ($self, $domain, $fn, $linenr, $msgid, $plural) = @_; my $textdomain = textdomain $domain; my $context = $textdomain->contextRules; foreach my $pot ($self->pots($domain)) { my ($stripped, $msgctxts); if($context) { my $lang = $pot->language || 'en'; ($stripped, $msgctxts) = $context->expand($msgid, $lang); if($plural && $plural =~ m/\{[^}]*\<\w+/) { error __x"no context tags allowed in plural `{msgid}'", msgid => $plural; } } else { $stripped = $msgid; } $msgctxts && @$msgctxts or $msgctxts = [undef]; MSGCTXT: foreach my $msgctxt (@$msgctxts) { if(my $po = $pot->msgid($stripped, $msgctxt)) { $po->addReferences( ["$fn:$linenr"]); $po->plural($plural) if $plural; next MSGCTXT; } my $format = $stripped =~ m/\{/ ? 'perl-brace' : 'perl'; my $po = Log::Report::Lexicon::PO->new( msgid => $stripped, msgid_plural => $plural, msgctxt => $msgctxt, fuzzy => 1, format => $format, references => [ "$fn:$linenr" ] ); $pot->add($po); } } } 1; Log-Report-Lexicon-1.15/t/0000755000175000001440000000000015103071406016007 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/t/40ppi.t0000644000175000001440000000520514775703615017154 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Extract PPI use warnings; use strict; use File::Temp qw/tempdir/; use Test::More; use constant MSGIDS => 25; use constant PLURAL_MSGIDS => 4; BEGIN { eval "require PPI"; plan skip_all => 'PPI not installed' if $@; plan tests => 10 + MSGIDS*4 + PLURAL_MSGIDS*1; use_ok('Log::Report::Extract::PerlPPI'); } my $lexicon = tempdir CLEANUP => 1; my %expect_pos = ('' => 1); # expect header sub take($@) { my $result = shift; ok("$result", "$result"); $expect_pos{$_}++ for @_; } ### my $ppi = Log::Report::Extract::PerlPPI->new(lexicon => $lexicon); ok(defined $ppi, 'created parser'); isa_ok($ppi, 'Log::Report::Extract::PerlPPI'); $ppi->process( __FILE__ ); # yes, this file! $ppi->write; my @potfns = $ppi->index->list('first-domain'); cmp_ok(scalar @potfns, '==', 1, "one file created"); my $potfn = shift @potfns; ok(defined $potfn); ok(-s $potfn, "produced file $potfn has size"); #### sub dummy($) {shift} use Log::Report 'first-domain'; # cannot use variable textdomain take("a0"); take(__"a1", 'a1'); take((__"a2"), 'a2'); take((__"a3a", "a3b"), 'a3a'); take(__("a4"), 'a4'); take(__ dummy('a7')); take(__ dummy 'a8'); take(__(dummy 'a9')); take((__x"b2"), 'b2'); take((__x"b3a", b2b => "b3c"), 'b3a'); take(__x("b4"), 'b4'); take(__x("b5a", b5b => "b5c"), 'b5a'); take(__x('b6a', b6b => "b6c"), 'b6a'); take(__x(qq{b7a}, b7b => "b7c"), 'b7a'); take(__x(q{b8a}, b8b => "b8c"), 'b8a'); take(__x(b9a => b9b => "b9c"), 'b9a'); take(__x(b10 => 1, 2), 'b10'); take((__n "c1", "c2", 1), "c1", "c2"); take((__n "c3", "c4", 0), "c3", "c4"); take(__n("c5", "c6", 1), "c5", "c6"); take(__n("c7", "c8", 0), "c7", "c8"); take(N__("d1"), "d1", "d1"); take(join(',', N__w("d2 d3")), "d2", "d3"); take(join(',', N__w(" d4 d5 d6 d7")), "d4", "d5", "d6", "d7"); # line contains tab ### do not index these: __x(+"e1"); ### check that all tags were found in POT my $pot = Log::Report::Lexicon::POT->read($potfn, charset => 'utf-8'); ok(defined $pot, 'read translation table'); my @pos = $pot->translations('ACTIVE'); ok(@pos > 0); cmp_ok(scalar @pos, '==', MSGIDS, 'correct number tests'); cmp_ok(scalar @pos, '==', scalar $pot->translations); # all active my %msgids; for my $po (@pos) { my $msgid = $po->msgid; ok(defined $msgid, "processing $msgid"); ok(!defined $msgids{$msgid}, 'check not double'); $msgids{$msgid}++; ok(delete $expect_pos{$msgid}, "was expected $msgid"); my $plural = $po->plural or next; ok(delete $expect_pos{$plural}, 'plural was expected'); } cmp_ok(scalar keys %expect_pos, '==', 0, "all msgids found"); warn "NOT FOUND: $_\n" for keys %expect_pos; Log-Report-Lexicon-1.15/t/simplecal/0000755000175000001440000000000015103071406017760 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/t/simplecal/fr.po0000644000175000001440000000330614775703615020753 0ustar00markovusers00000000000000# French translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:07+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "janvier" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "fvrier" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "mars" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "avril" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "mai" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "juin" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "juillet" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "aot" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "septembre" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "octobre" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "novembre" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "dcembre" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "di" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "lu" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "ma" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "me" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "je" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "ve" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "sa" #~ msgid "Welcome to {package}!\n" #~ msgstr "Bienvenu {package}!\n" #~ msgid "Bye.\n" #~ msgstr " toute l'heure!\n" Log-Report-Lexicon-1.15/t/simplecal/ar.po0000644000175000001440000000325514775703615020751 0ustar00markovusers00000000000000# Arabic translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-27 18:56+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Arabic \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-6\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "" #~ msgid "Welcome to {package}!\n" #~ msgstr " {package} \n" #~ msgid "Bye.\n" #~ msgstr "! \n" Log-Report-Lexicon-1.15/t/simplecal/pt.po0000644000175000001440000000332514775703615020770 0ustar00markovusers00000000000000# Portuguese translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:24+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "Janeiro" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "Fevereiro" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "Maro" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "Abril" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "Maio" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "Junho" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "Julho" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "Agosto" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "Setembro" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "Outubro" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "Novembro" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "Dezembro" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "Dom" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "Seg" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "Ter" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "Qua" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "Qui" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "Sex" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "Sb" #~ msgid "Welcome to {package}!\n" #~ msgstr "Bem-vindo ao {package}!\n" #~ msgid "Bye.\n" #~ msgstr "At a vista!\n" Log-Report-Lexicon-1.15/t/simplecal/nl.po0000644000175000001440000000327414775703615020761 0ustar00markovusers00000000000000# Dutch translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:08+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "januari" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "februari" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "maart" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "april" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "mei" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "juni" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "juli" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "augustus" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "september" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "oktober" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "november" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "december" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "zo" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "ma" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "di" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "wo" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "do" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "vr" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "za" #~ msgid "Welcome to {package}!\n" #~ msgstr "Welkom bij {package}!\n" #~ msgid "Bye.\n" #~ msgstr "Tot zo!\n" Log-Report-Lexicon-1.15/t/simplecal/de_AT.po0000644000175000001440000000306714775703615021324 0ustar00markovusers00000000000000# German (Austria) translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-27 18:47+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "Jnner" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "Feber" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "" Log-Report-Lexicon-1.15/t/simplecal/ru.po0000644000175000001440000000330714775703615020773 0ustar00markovusers00000000000000# Russian translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:21+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-5\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "" #~ msgid "Welcome to {package}!\n" #~ msgstr " {package}!\n" #~ msgid "Bye.\n" #~ msgstr "!\n" Log-Report-Lexicon-1.15/t/simplecal/it.po0000644000175000001440000000331614775703615020761 0ustar00markovusers00000000000000# Italian translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:10+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "gennaio" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "febbraio" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "marzo" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "aprile" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "maggio" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "giugno" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "luglio" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "agosto" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "settembre" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "ottobre" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "novembre" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "dicembre" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "dom" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "lun" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "mar" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "mer" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "gio" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "ven" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "sab" #~ msgid "Welcome to {package}!\n" #~ msgstr "Benvenuti in {package}!\n" #~ msgid "Bye.\n" #~ msgstr "Ciao!\n" Log-Report-Lexicon-1.15/t/simplecal/de.po0000644000175000001440000000342214775703615020733 0ustar00markovusers00000000000000# German translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: Edit the file PACAKGE to change this.\n" "POT-Creation-Date: 2005-08-16 18:42+0300\n" "PO-Revision-Date: 2003-07-28 04:06+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "Januar" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "Februar" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "Mrz" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "April" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "Mai" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "Juni" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "Juli" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "August" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "September" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "Oktober" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "November" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "Dezember" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "So" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "Mo" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "Di" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "Mi" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "Do" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "Fr" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "Sa" #~ msgid "Welcome to {package}!\n" #~ msgstr "Willkommen bei {package}!\n" #~ msgid "Bye.\n" #~ msgstr "Tschss!\n" Log-Report-Lexicon-1.15/t/simplecal/ar_SA.mo0000644000175000001440000000145214775703615021326 0ustar00markovusers00000000000000 017>GPX]bhlu }F    $    AprilAugustDecemberFebruaryJanuaryJulyJuneMarchMayNovemberOctoberSeptemberProject-Id-Version: SimpleCal Report-Msgid-Bugs-To: POT-Creation-Date: 2003-07-28 04:27+0200 PO-Revision-Date: 2003-07-27 18:56+0200 Last-Translator: Guido Flohr Language-Team: Arabic MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-6 Content-Transfer-Encoding: 8bit Log-Report-Lexicon-1.15/t/simplecal/pt_BR.po0000644000175000001440000000316114775703615021351 0ustar00markovusers00000000000000# Brazilian Portuguese translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-27 18:56+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "janeiro" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "fevereiro" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "maro" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "abril" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "maio" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "junho" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "julho" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "agosto" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "setembro" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "outubro" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "novembro" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "dezembro" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "Dom" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "Seg" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "Ter" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "Qua" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "Qui" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "Sex" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "Sb" Log-Report-Lexicon-1.15/t/simplecal/README0000644000175000001440000000030314775703615020656 0ustar00markovusers00000000000000The files in this directory are taken from the Locale::TextDomain example. It is stripped to contain only some PO-files to test the correct processing of character-sets by Log::Report::Lexicon. Log-Report-Lexicon-1.15/t/simplecal/cs.po0000644000175000001440000000334514775703615020754 0ustar00markovusers00000000000000# Czech translations for SimpleCal. # Copyright (C) 2012 Jan Tomasek . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: Edit the file PACAKGE to change this.\n" "POT-Creation-Date: 2005-08-17 11:53+0300\n" "PO-Revision-Date: 2003-07-28 04:21+0200\n" "Last-Translator: Jan Tomášek \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "Leden" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "Únor" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "Březen" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "Duben" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "Květen" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "Červen" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "Červenec" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "Září" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "Říjen" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "Listopad" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "Prosinec" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "Prosinec" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "Ne" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "Po" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "Út" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "St" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "Čt" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "Pá" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "So" #~ msgid "Welcome to {package}!\n" #~ msgstr "Vítejte v {package}!\n" #~ msgid "Bye.\n" #~ msgstr "Nashledanou!\n" Log-Report-Lexicon-1.15/t/simplecal/ga.po0000644000175000001440000000337214775703615020736 0ustar00markovusers00000000000000# Irish translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-28 04:10+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Irish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr "Eanir" #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "Feabhra" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "Mrta" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "Aibren" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "M na Bealtaine" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "Meith" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "Iil" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "Lnasa" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "Men Fmhair" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr "Deireadh Fmhair" #: ../lib/SimpleCal.pm:46 msgid "November" msgstr "M na Samhna" #: ../lib/SimpleCal.pm:48 msgid "December" msgstr "M na Nollag" #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "Domh" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "Luan" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "Mirt" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "Cad" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "Dar" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "Aoine" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "Sath" #~ msgid "Welcome to {package}!\n" #~ msgstr "Bidh {package} agat agus filte!\n" #~ msgid "Bye.\n" #~ msgstr "Sln leat!\n" Log-Report-Lexicon-1.15/t/simplecal/ar_SA.po0000644000175000001440000000310314775703615021324 0ustar00markovusers00000000000000# Arabic translations for SimpleCal. # Copyright (C) 2003 Imperia AG, Guido Flohr . # This file is distributed under the same license as libintl-perl. # msgid "" msgstr "" "Project-Id-Version: SimpleCal\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-07-28 04:27+0200\n" "PO-Revision-Date: 2003-07-27 18:56+0200\n" "Last-Translator: Guido Flohr \n" "Language-Team: Arabic \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-6\n" "Content-Transfer-Encoding: 8bit\n" #: ../lib/SimpleCal.pm:26 msgid "January" msgstr " " #: ../lib/SimpleCal.pm:28 msgid "February" msgstr "" #: ../lib/SimpleCal.pm:30 msgid "March" msgstr "" #: ../lib/SimpleCal.pm:32 msgid "April" msgstr "" #: ../lib/SimpleCal.pm:34 msgid "May" msgstr "" #: ../lib/SimpleCal.pm:36 msgid "June" msgstr "" #: ../lib/SimpleCal.pm:38 msgid "July" msgstr "" #: ../lib/SimpleCal.pm:40 msgid "August" msgstr "" #: ../lib/SimpleCal.pm:42 msgid "September" msgstr "" #: ../lib/SimpleCal.pm:44 msgid "October" msgstr " " #: ../lib/SimpleCal.pm:46 msgid "November" msgstr " " #: ../lib/SimpleCal.pm:48 msgid "December" msgstr " " #: ../lib/SimpleCal.pm:70 msgid "Sun" msgstr "" #: ../lib/SimpleCal.pm:71 msgid "Mon" msgstr "" #: ../lib/SimpleCal.pm:72 msgid "Tue" msgstr "" #: ../lib/SimpleCal.pm:73 msgid "Wed" msgstr "" #: ../lib/SimpleCal.pm:74 msgid "Thu" msgstr "" #: ../lib/SimpleCal.pm:75 msgid "Fri" msgstr "" #: ../lib/SimpleCal.pm:76 msgid "Sat" msgstr "" Log-Report-Lexicon-1.15/t/41templ.t0000644000175000001440000000431114775703615017503 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Extract templates use warnings; use strict; use File::Temp qw/tempdir/; use Test::More; use Log::Report; # mode => 'DEBUG'; use Log::Report::Lexicon::POT; use Log::Report::Extract::Template; use constant MSGIDS => 12; # see after __END__ my @expect_pos = split /\n/, <<'_EXPECT'; first second third fourth fifth six six six %d seven eight nine tenth {a} eleven twelve {b} _EXPECT chomp $expect_pos[-1]; cmp_ok(scalar @expect_pos, '==', MSGIDS); my %expect_pos = map { ($_ => 1) } @expect_pos; $expect_pos{''} = 1; # header BEGIN { plan tests => 15 + MSGIDS*3; } my $lexicon = tempdir CLEANUP => 1; my $extr = Log::Report::Extract::Template->new ( lexicon => $lexicon , domain => 'my-domain' , pattern => 'TT2-loc' ); ok(defined $extr, 'created parser'); isa_ok($extr, 'Log::Report::Extract::Template'); my $found = $extr->process( __FILE__ ); # yes, this file! cmp_ok($found, '==', MSGIDS); $extr->write; my @potfns = $extr->index->list('my-domain'); cmp_ok(scalar @potfns, '==', 1, "one file created"); my $potfn = shift @potfns; ok(defined $potfn); ok(-s $potfn, "produced file $potfn has size"); #system "cat $potfn"; my $pot = Log::Report::Lexicon::POT->read($potfn, charset => 'utf-8'); ok(defined $pot, 'read translation table'); my @pos = $pot->translations('ACTIVE'); ok(@pos > 0); # (+1 for the header) cmp_ok(scalar @pos, '==', MSGIDS+1, 'correct number tests'); cmp_ok(scalar @pos, '==', scalar $pot->translations); # all active my %msgids; for my $po (@pos) { my $msgid = $po->msgid; ok(defined $msgid, "processing '$msgid'"); ok(!defined $msgids{$msgid}, 'check not double'); $msgids{$msgid}++; ok(delete $expect_pos{$msgid}, 'was expected'); } cmp_ok(scalar keys %expect_pos, '==', 0, "all msgids found"); warn "NOT FOUND: $_\n" for keys %expect_pos; __END__ Here, the example template starts [%loc("first")%] [%loc("second")%] [%loc('third')%] [% loc ( 'fourth' ) %] [% loc ( 'fifth' , params ) %] [%xloc('not found')%] [%loc('six six six')%] [% loc('%d seven|%d sevens', 7) %] [% INCLUDE header.tt title = loc("eight") loc ('nine' ) css =loc( 'tenth' ) %] [% '{a} eleven' | loc(a => 3) %] [%| loc(b=>4) %]twelve {b}[%END%] Log-Report-Lexicon-1.15/t/20pot_read.t0000644000175000001440000000602614775703615020161 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Lexicon POT use warnings; use strict; use lib 'lib', '../lib'; use utf8; use Test::More tests => 47; use File::Basename qw/dirname/; use File::Spec::Functions qw/catfile/; use Encode qw/is_utf8/; use_ok('Log::Report::Lexicon::PO'); use_ok('Log::Report::Lexicon::POT'); my $sl_po = catfile(dirname(__FILE__), 'hello-world-slovak.po'); # # Try reading complex example # slightly modified from gettext examples in slovak # my $pot = Log::Report::Lexicon::POT->read($sl_po, charset => 'utf-8'); ok(defined $pot, "read pot file"); isa_ok($pot, 'Log::Report::Lexicon::POT'); # # header # is($pot->header('mime-version'), '1.0', 'access to header'); # # plurals # cmp_ok($pot->nrPlurals, '==', 4, 'test plural evaluation'); cmp_ok($pot->pluralIndex(0), '==', 0); cmp_ok($pot->pluralIndex(1), '==', 1); cmp_ok($pot->pluralIndex(2), '==', 2); cmp_ok($pot->pluralIndex(3), '==', 3); cmp_ok($pot->pluralIndex(4), '==', 3); cmp_ok($pot->pluralIndex(5), '==', 0); cmp_ok($pot->pluralIndex(6), '==', 0); cmp_ok($pot->pluralIndex(101), '==', 1); # # extended single case # my $po = $pot->msgid('Hello, world!'); ok(defined $po, "got greeting"); isa_ok($po, 'Log::Report::Lexicon::PO'); is($po->msgid, 'Hello, world!'); ok(!defined $po->plural); is($po->comment, 'translator comment translator comment line 2 '); is($po->automatic, 'automatic comment automatic comment line 2 '); my @refs = sort $po->references; cmp_ok(scalar @refs, '==', 4); is($refs[0], 'bis'); is($refs[1], 'hello-1.pl.in:18'); is($refs[2], 'hello-1.pl.in:20'); is($refs[3], 'hello-2.pl.in:13'); is($po->msgstr, "Pozdravljen, svet!"); is($po->msgstr(0), "Pozdravljen, svet!"); is($po->msgstr(1), "Pozdravljen, svet!"); # index gets ignored is($pot->msgstr("Hello, world!"), "Pozdravljen, svet!"); is($pot->msgstr("Hello, world!", 0), "Pozdravljen, svet!"); is($po->toString, <<'__DUMP'); # translator comment # translator comment line 2 #. automatic comment #. automatic comment line 2 #: bis hello-1.pl.in:18 hello-1.pl.in:20 hello-2.pl.in:13 msgid "Hello, world!" msgstr "Pozdravljen, svet!" __DUMP # # with plurals # is($pot->msgstr('Aap', 0), 'A', 'msgstr by plural'); is($pot->msgstr('Aap', 1), 'B'); is($pot->msgstr('Aap', 2), 'C'); is($pot->msgstr('Aap', 3), 'D'); is($pot->msgstr('Aap', 4), 'D'); is($pot->msgstr('Aap', 5), 'A'); is($pot->msgstr('Aap', 6), 'A'); is($pot->msgstr('Aap', 100), 'A'); is($pot->msgstr('Aap', 101), 'B'); is($pot->msgid('Aap')->plural, 'Apen'); # # with multi-lines and utf # my $po2 = $pot->msgid("This program is running as process number {pid}.multi-line\n"); ok(defined $po2, 'test multi'); my $po2t = $po2->msgstr; is($po2t, "Ta program teče kot proces številka {pid}.multi\tline\n"); ok(is_utf8($po2t), 'is utf8'); # ### READ charset detect # my $ar_fn = catfile dirname(__FILE__), simplecal => 'ar.po'; my $ar = Log::Report::Lexicon::POT->read($ar_fn); cmp_ok scalar $ar->translations, '==', 22; my $ar_po = $ar->msgid('December'); isa_ok $ar_po, 'Log::Report::Lexicon::PO'; is $ar_po->msgstr, 'ديسمبر'; Log-Report-Lexicon-1.15/t/04locale.t0000644000175000001440000000323115103070401017570 0ustar00markovusers00000000000000#!/usr/bin/env perl # test locale use Test::More; use POSIX; use locale; my $alt_locale; BEGIN { eval "POSIX->import( qw/setlocale :locale_h/ )"; # locale disabled? defined setlocale(LC_ALL, 'C') or plan skip_all => "no translation support in Perl or OS"; LOCALE: foreach my $l (qw/nl_NL de_DE pt_PT tr_TR/) # only non-english! { foreach my $c ('utf-8', 'iso-8859-1', '') { $alt_locale = $c ? "$l.$c" : $l; my $old = setlocale LC_ALL, $alt_locale; my $set = setlocale LC_ALL, $alt_locale; last LOCALE if defined $set && $set eq $alt_locale; } undef $alt_locale; } defined $alt_locale or plan skip_all => "cannot find alternative language for tests"; plan tests => 10; } ok(1, "alt locale: $alt_locale"); ok(defined setlocale(LC_ALL, 'C'), 'set C'); my $try = setlocale(LC_ALL); ok(defined $try, 'explicit C found'); ok($try eq 'C' || $try eq 'POSIX'); $! = 2; my $err_posix = "$!"; ok(defined $err_posix, $err_posix); # english my $change = setlocale LC_ALL, $alt_locale; ok(defined $change, "returned change to alternative locale"); is(setlocale(LC_ALL), $alt_locale, "set to $alt_locale successful?"); $! = 2; my $err_alt = "$!"; ok(defined $err_alt, $err_alt); if($err_posix eq $err_alt) { # some platforms have mistakes in their language configuration ok(1, "ERROR: libc translations not switched"); warn "*** ERROR: changing language of libc error messages did not work\n"; sleep 1; } else { ok(1, "libc does translate standard errors"); } setlocale(LC_ALL, 'C'); $! = 2; my $err_posix2 = "$!"; is($err_posix, $err_posix2, $err_posix2); Log-Report-Lexicon-1.15/t/00use.t0000644000175000001440000000205415057554210017140 0ustar00markovusers00000000000000#!/usr/bin/env perl use warnings; use strict; use Test::More; # The versions of the following packages are reported to help understanding # the environment in which the tests are run. This is certainly not a # full list of all installed modules. my @show_versions = qw/PPI POSIX Test::Pod Log::Report::Optional Log::Report String::Print /; warn "Perl $]\n"; foreach my $package (sort @show_versions) { eval "require $package"; my $report = !$@ ? "version ". ($package->VERSION || 'unknown') : $@ =~ m/^Can't locate/ ? "not installed" : "reports error"; warn "$package $report\n"; } use_ok('Log::Report'); use_ok('Log::Report::Extract'); use_ok('Log::Report::Lexicon::Index'); use_ok('Log::Report::Lexicon::PO'); use_ok('Log::Report::Lexicon::POT'); use_ok('Log::Report::Lexicon::POTcompact'); use_ok('Log::Report::Translator::Context'); use_ok('Log::Report::Translator'); use_ok('Log::Report::Translator::POT'); # Log::Report::Extract::PerlPPI requires optional PPI done_testing; Log-Report-Lexicon-1.15/t/22compact.t0000644000175000001440000000320414775703615020007 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Lexicon POTcompact # Structure of parsed result has also been checked manually, using # Data::Dumper (MO 2007/05/11) use warnings; use strict; use lib 'lib', '../lib'; use utf8; use Test::More tests => 21; use File::Basename qw/dirname/; use File::Spec::Functions qw/catfile/; use_ok('Log::Report::Lexicon::POTcompact'); my $sl_po = catfile(dirname(__FILE__), 'hello-world-slovak.po'); # # Try reading complex example # slightly modified from gettext examples in slovak # my $pot = Log::Report::Lexicon::POTcompact->read($sl_po, charset => 'utf-8'); ok(defined $pot, "read pot file"); isa_ok($pot, 'Log::Report::Lexicon::POTcompact'); # # header # is($pot->header('mime-version'), '1.0', 'access to header'); # # extended single case # my $po = $pot->msgid('Hello, world!'); ok(defined $po, "got greeting"); ok(!ref $po, "one translation only"); is($po, "Pozdravljen, svet!"); is($pot->msgstr("Hello, world!"), "Pozdravljen, svet!"); is($pot->msgstr("Hello, world!", 0), "Pozdravljen, svet!"); is($pot->msgstr("Hello, world!", 5), "Pozdravljen, svet!"); # # with plurals # is($pot->msgstr('Aap', 0), 'A', 'msgstr by plural'); is($pot->msgstr('Aap', 1), 'B'); is($pot->msgstr('Aap', 2), 'C'); is($pot->msgstr('Aap', 3), 'D'); is($pot->msgstr('Aap', 4), 'D'); is($pot->msgstr('Aap', 5), 'A'); is($pot->msgstr('Aap', 6), 'A'); is($pot->msgstr('Aap', 100), 'A'); is($pot->msgstr('Aap', 101), 'B'); # # with multi-lines and utf # my $po2 = $pot->msgid("This program is running as process number {pid}.multi-line\n"); ok(defined $po2, 'test multi'); is($po2, "Ta program teče kot proces številka {pid}.multi\tline\n"); Log-Report-Lexicon-1.15/t/41ppi_imports.t0000644000175000001440000000346615103071403020714 0ustar00markovusers00000000000000#!/usr/bin/env perl # Test that we can cope with all of the ways of specifying a text domain. use warnings; use strict; use Cwd; use File::Temp qw/tempdir/; use Test::More; BEGIN { eval "require PPI"; $@ and plan skip_all => 'PPI not installed'; use_ok 'Log::Report::Extract::PerlPPI'; } _test_import( subtest_name => 'Preceded by a version number', source => 'use Log::Report 1.00 "not-a-version-number";', text_domain => 'not-a-version-number', ); _test_import( subtest_name => 'Using a quotelike operator', source => 'use Log::Report qw(wossname)', text_domain => 'wossname', ); _test_import( subtest_name => 'The Dancer plugin works as well', source => q{use Dancer2::Plugin::LogReport 'dance-monkey-dance';}, text_domain => 'dance-monkey-dance', ); _test_import( subtest_name => 'With no arguments at all', source => 'use Log::Report', text_domain => undef, ); done_testing(); sub _test_import { my (%args) = @_; subtest $args{subtest_name} => sub { my $source_dir = tempdir CLEANUP => 1; my $lexicon = tempdir CLEANUP => 1; my $ppi = Log::Report::Extract::PerlPPI->new(lexicon => $lexicon); my $previous_cwd = Cwd::cwd(); chdir($source_dir); open (my $fh, '>', 'perl-source.pl'); print $fh $args{source}; close $fh; $ppi->process('perl-source.pl'); $ppi->write; my @leafnames = keys %{ $ppi->index->index }; if (defined $args{text_domain}) { is @leafnames, 1, 'We added a file'; like $leafnames[0], qr/^$args{text_domain}/, '...matching the expected text domain'; } else { is @leafnames, 0, 'No text domain = no files added'; } chdir($previous_cwd); }; } Log-Report-Lexicon-1.15/t/12test/0000755000175000001440000000000015103071406017131 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/t/12test/en_US.UTF-8.po0000644000175000001440000000236414775703615021333 0ustar00markovusers00000000000000#. Header generated with Log::Report::Lexicon::POT 0.0 msgid "" msgstr "" "Project-Id-Version: my-domain 0.01\n" "Report-Msgid-Bugs-To:\n" "POT-Creation-Date: 2013-12-12 08:37+0100\n" "PO-Revision-Date: 2013-12-12 08:37+0100\n" "Last-Translator: Mark Overmeer\n" "Language-Team:\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" #: t/11ppiexp.t:60 msgctxt "gender=female style=formal" msgid "Dear Sir," msgid_plural "Dear Sirs," msgstr[0] "Dear Lady," msgstr[1] "Dear Ladies," #: t/11ppiexp.t:60 msgctxt "gender=male style=formal" msgid "Dear Sir," msgid_plural "Dear Sirs," msgstr[0] "" msgstr[1] "" #: t/11ppiexp.t:60 msgctxt "gender=female style=informal" msgid "Dear Sir," msgid_plural "Dear Sirs," msgstr[0] "Hi love," msgstr[1] "Hi darlin's," #: t/11ppiexp.t:60 msgctxt "gender=male style=informal" msgid "Dear Sir," msgid_plural "Dear Sirs," msgstr[0] "Dear friend," msgstr[1] "Hi friends," #: t/11ppiexp.t:63 msgid "no context {where}" msgstr "out of context {where}" #: t/11ppiexp.t:57 msgctxt "gender=female" msgid "{name} forgot his key" msgstr "{name} forgot her key" #: t/11ppiexp.t:57 msgctxt "gender=male" msgid "{name} forgot his key" msgstr "" Log-Report-Lexicon-1.15/t/30index.t0000644000175000001440000000465114775703615017476 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Lexicon index: discover files and character encodings use warnings; use strict; use lib 'lib', '../lib'; use utf8; use Test::More tests => 71; use File::Basename qw/dirname/; use File::Spec::Functions qw/catfile/; use Data::Dumper qw/Dumper/; $Data::Dumper::Indent = 1; $Data::Dumper::Quotekeys = 0; use_ok 'Log::Report::Translator::POT'; use_ok 'Log::Report::Lexicon::Index'; my $lexdir = dirname(__FILE__); my $pot = Log::Report::Translator::POT->new(lexicons => $lexdir); isa_ok $pot, 'Log::Report::Translator::POT'; my @lexicons = $pot->lexicons; cmp_ok scalar @lexicons, '==', 1, 'found 1 lexicon'; my $lexicon = shift @lexicons; isa_ok $lexicon, 'Log::Report::Lexicon::Index'; is $lexicon->directory, $lexdir; my $i = $lexicon->index; #warn Dumper $i; ### test the list() method my @list1 = $lexicon->list('simplecal'); cmp_ok scalar @list1, '==', 13, 'list simplecal'; my @list2 = $lexicon->list('simplecal', 'po'); cmp_ok scalar @list2, '==', 12, 'list simplecal po'; ### test the find() method my $fn0 = $lexicon->find('simplecal', 'nl'); ok defined $fn0, "found NL in $fn0"; defined $fn0 or warn Dumper $lexicon; my $fn1 = $lexicon->find('simplecal', 'nl_BE'); ok defined $fn1, "found nl_BE in $fn1"; ### get file opened with correct charset my @pots = ( [ ar => 'iso-8859-6' => 'نوفمبر' ] , [ ar_sa => 'iso-8859-6' => 'تشرين الثاني' ] , [ cs => 'UTF-8' => 'Prosinec' ] , [ de => 'iso-8859-1' => 'November' ] , [ de_at => 'iso-8859-1' => '' ] , [ fr => 'iso-8859-1' => 'novembre' ] , [ ga => 'iso-8859-1' => 'Mí na Samhna' ] , [ it => 'iso-8859-1' => 'novembre' ] , [ nl => 'iso-8859-1' => 'november' ] , [ pt => 'iso-8859-1' => 'Novembro' ] , [ pt_br => 'iso-8859-1' => 'novembro' ] , [ ru => 'ISO-8859-5' => 'Ноября' ] ); foreach (@pots) { my ($lang, $charset, $trans) = @$_; my $po = $pot->load('simplecal', $lang); ok defined $po, "got translation for $lang"; like $po->filename, qr/$lang\.[mp]o$/i, 'filename '.$po->filename; isa_ok $po, $lang eq 'ar_sa' ? 'Log::Report::Lexicon::MOTcompact' : 'Log::Report::Lexicon::POTcompact'; is $po->originalCharset, $charset, "charset $lang"; is $po->msgid('November'), $trans, "translated $lang"; } my $msg = {_domain => 'simplecal', _msgid => 'November'}; is $pot->translate($msg, 'ru', undef), 'Ноября'; Log-Report-Lexicon-1.15/t/hello-world-slovak.po0000644000175000001440000000243114775703615022116 0ustar00markovusers00000000000000# -*- mode: po; coding: utf-8; -*- Slovenian message catalog for GNU gettext-example msgid "" msgstr "" "Project-Id-Version: hello-perl 0.14.5\n" "Report-Msgid-Bugs-To: bug-gnu-gettext@gnu.org\n" "POT-Creation-Date: 2007-04-18 15:27+0200\n" "PO-Revision-Date: 2005-09-29 13:38+0200\n" "Last-Translator: Primož Peterlin \n" "Language-Team: Slovenian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" "%100==4 ? 3 : 0);\n" # translator comment # translator comment line 2 #. automatic comment #. automatic comment line 2 #: hello-1.pl.in:20 #: hello-1.pl.in:18 hello-2.pl.in:13 #: hello-1.pl.in:20 bis msgid "Hello, world!" msgstr "Pozdravljen, svet!" #: hello-1.pl.in:20 #, perl-format msgid "This program is running as process number %d." msgstr "Ta program teče kot proces številka %d." #: hello-2.pl.in:16 #, perl-brace-format msgid "This program is running as process number {pid}." "multi-line\n" msgstr "Ta program teče kot proces številka {pid}." "multi\tline\n" #: hello-2.pl.in:17 msgid "Aap" msgid_plural "Apen" msgstr[0] "A" msgstr[1] "B" msgstr[2] "C" msgstr[3] "D" Log-Report-Lexicon-1.15/t/12ctxt.t0000644000175000001440000000525214777242251017343 0ustar00markovusers00000000000000#!/usr/bin/env perl # This tries to use context dependent translations use warnings; use strict; use Test::More; use Log::Report '12test'; # domain selects table use File::Spec::Functions qw/catdir/; use File::Basename qw/dirname/; use POSIX qw/:locale_h/; # The test file was produced by the t/11 script, and then filled in by hand if($^O eq 'openbsd') { plan skip_all => "openbsd does not support LC_ALL"; exit 0; } my $got_locale = setlocale LC_ALL, 'en_US.UTF-8'; $got_locale && $got_locale eq 'en_US.UTF-8' or plan skip_all => "cannot set an en_US.UTF-8 locale"; plan tests => 16; use_ok 'Log::Report::Translator::POT'; my $rules = { gender => [ 'male', 'female' ] , style => [ 'informal', 'formal' ] }; my $translator = Log::Report::Translator::POT->new(lexicon => (dirname __FILE__)); my $domain = textdomain '12test', context_rules => $rules, translator => $translator; isa_ok $domain, 'Log::Report::Domain', 'recreated'; $domain->setContext('gender=male, style=informal'); # # Simpelest, no context # my $d1 = __x"no context {where}", where => 'here'; is $d1, 'out of context here'; # # Single context "gender", various parameter formats # my $a1 = __x"{name 'Mark'; is $a1, 'Mark forgot his key'; my $a2 = __x"{name 'Cleo', _context => 'gender=female'; is $a2, 'Cleo forgot her key'; my $a3 = __x"{name 'Hillary', _context => {gender =>'female'}; is $a3, 'Hillary forgot her key'; my $a4 = __x"{name 'Piet', _context => {gender => 'male'}; is $a4, 'Piet forgot his key'; # # Two contexts and count # my $b1 = __xn"Dear Sir,{ 'gender=female'; is $b2, "Hi darlin's,"; my $b3 = __xn"Dear Sir,{ 'style=formal'; is $b3, 'Dear Sirs,'; my $b4 = __xn"Dear Sir,{ 'gender=female,style=formal'; is $b4, 'Dear Ladies,'; my $b5 = __xn"Dear Sir,{ 'gender=female'; is $b6, "Hi love,"; my $b7 = __xn"Dear Sir,{ 'style=formal'; is $b7, 'Dear Sir,'; my $b8 = __xn"Dear Sir,{ 'gender=female,style=formal'; is $b8, 'Dear Lady,'; # Context values also available to insert my $c1 = __x"{name} is a {_context.gender}", name => 'Piet', _context => {gender => 'male'}; is $c1, 'Piet is a male'; Log-Report-Lexicon-1.15/t/21pot_modif.t0000644000175000001440000001027714775703615020350 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Lexicon PO modifications use warnings; use strict; use utf8; use Test::More tests => 29; use_ok('Log::Report::Lexicon::PO'); use_ok('Log::Report::Lexicon::POT'); # # Create header # $Log::Report::VERSION = 'SOME_VERSION'; my $pot = Log::Report::Lexicon::POT->new ( textdomain => 'log-report' , version => '2.3' , charset => 'UTF-8' , date => 'DUMMY' # don't want this to change during test ); is($pot->msgstr(''), <<'__HEADER'); Project-Id-Version: log-report 2.3 Report-Msgid-Bugs-To: POT-Creation-Date: DUMMY PO-Revision-Date: DUMMY Last-Translator: Language-Team: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n!=1); __HEADER is($pot->msgid('')->toString, <<'__HEAD'); #. Header generated with Log::Report::Lexicon::POT SOME_VERSION msgid "" msgstr "" "Project-Id-Version: log-report 2.3\n" "Report-Msgid-Bugs-To:\n" "POT-Creation-Date: DUMMY\n" "PO-Revision-Date: DUMMY\n" "Last-Translator:\n" "Language-Team:\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" __HEAD cmp_ok($pot->nrPlurals, "==", 2); is($pot->header('mime-version'), '1.0'); is($pot->header('mime-version', '3.14'), '3.14'); is($pot->header('mime-version'), '3.14'); is($pot->header('mime-version', undef), undef); is($pot->header('new-field', 'some value'), 'some value'); $pot->updated('NEWDATE'); is($pot->msgid('')->toString, <<'__HEAD'); #. Header generated with Log::Report::Lexicon::POT SOME_VERSION msgid "" msgstr "" "Project-Id-Version: log-report 2.3\n" "Report-Msgid-Bugs-To:\n" "POT-Creation-Date: DUMMY\n" "PO-Revision-Date: NEWDATE\n" "Last-Translator:\n" "Language-Team:\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "new-field: some value\n" __HEAD # # Create non-plural # my $po = Log::Report::Lexicon::PO->new ( msgid => 'aap' , references => 'aap.pm:10' ); is($po->toString, <<'__AAP', 'no translation'); #: aap.pm:10 msgid "aap" msgstr "" __AAP $po->addReferences('monkey.pm:12 aap.pm:3'); $po->msgstr(0, 'monkey'); is($po->toString, <<'__AAP', 'with translation'); #: aap.pm:10 aap.pm:3 monkey.pm:12 msgid "aap" msgstr "monkey" __AAP is($po->plural("apen"), 'apen', 'add plural'); ok($po->fuzzy(1), 'is fuzzy'); is($po->toString, <<'__AAP'); #: aap.pm:10 aap.pm:3 monkey.pm:12 #, fuzzy msgid "aap" msgid_plural "apen" msgstr[0] "monkey" msgstr[1] "" __AAP is($po->toString(nr_plurals => $pot->nrPlurals), <<'__AAP'); #: aap.pm:10 aap.pm:3 monkey.pm:12 #, fuzzy msgid "aap" msgid_plural "apen" msgstr[0] "monkey" msgstr[1] "" __AAP $po->msgstr(1, 'monkeys'); $po->fuzzy(0); cmp_ok($po->removeReferencesTo('aap.pm'), '==', 1); is($po->toString(nr_plurals => $pot->nrPlurals), <<'__AAP'); #: monkey.pm:12 msgid "aap" msgid_plural "apen" msgstr[0] "monkey" msgstr[1] "monkeys" __AAP # # Index # ok(!$pot->msgid('aap')); is($pot->add($po), $po, 'add'); is($pot->msgid('aap'), $po); is($pot->msgstr('aap', 0), 'monkeys'); is($pot->msgstr('aap', 1), 'monkey'); is($pot->msgstr('aap', 2), 'monkeys'); # # disable/enable # cmp_ok($po->removeReferencesTo('monkey.pm'), "==", 0, 'rm last ref'); is($po->toString(nr_plurals => $pot->nrPlurals), <<'__AAP'); #~ msgid "aap" #~ msgid_plural "apen" #~ msgstr[0] "monkey" #~ msgstr[1] "monkeys" __AAP $po->addReferences('noot.pm:12', 'aap.pm:42'); is($po->toString(nr_plurals => $pot->nrPlurals), <<'__AAP'); #: aap.pm:42 noot.pm:12 msgid "aap" msgid_plural "apen" msgstr[0] "monkey" msgstr[1] "monkeys" __AAP # # Write # my $text = ''; open TEXT, '>:utf8', \$text; $pot->write(\*TEXT); close TEXT; is($text, <<'__ALL') #. Header generated with Log::Report::Lexicon::POT SOME_VERSION msgid "" msgstr "" "Project-Id-Version: log-report 2.3\n" "Report-Msgid-Bugs-To:\n" "POT-Creation-Date: DUMMY\n" "PO-Revision-Date: NEWDATE\n" "Last-Translator:\n" "Language-Team:\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "new-field: some value\n" #: aap.pm:42 noot.pm:12 msgid "aap" msgid_plural "apen" msgstr[0] "monkey" msgstr[1] "monkeys" __ALL Log-Report-Lexicon-1.15/t/10context.t0000644000175000001440000000522314775703615020045 0ustar00markovusers00000000000000#!/usr/bin/env perl # Check message context parsing and checking use warnings; use strict; use lib 'lib', '../lib'; use Test::More tests => 14; use Log::Report; use Log::Report::Translator; use Log::Report::Translator::Context; my $rules = +{ style => [ 'informal', 'formal' ] , gender => [ 'male', 'female', 'unknown' ] , gender2 => { alternatives => [ 'male', 'female' ] } , gender3 => { default => { male => 'm1' , female => 'f1' , unknown => 'm1' } , nl => { unknown => 'x' } } }; #use JSON; #warn JSON->new->pretty->encode(\%config); my $context = Log::Report::Translator::Context->new(rules => $rules); is_deeply [$context->expand('a{b 'en')] , [ 'a{b}c', [ 'gender=female', 'gender=male', 'gender=unknown' ]] , 'simple gender'; is_deeply [$context->ctxtFor(__('a{b 'en', {gender => 'male'})] , [ 'a{b}c', 'gender=male' ]; is_deeply [$context->expand('a{ 'en')] , [ 'ab', [ 'style=formal', 'style=informal']] , 'simple boolean'; is_deeply [$context->ctxtFor(__('a{ 'en', {style => 'formal'})] , [ 'ac', 'style=formal' ]; is_deeply [$context->ctxtFor(__('a{ 'en', {style => 'informal'})] , [ 'ac', 'style=informal' ]; is_deeply [ $context->expand("a{b 'en') ] , [ 'a{b%2f}c' , [ 'gender=female style=formal' , 'gender=female style=informal' , 'gender=male style=formal' , 'gender=male style=informal' , 'gender=unknown style=formal' , 'gender=unknown style=informal' ] ] , 'combination explosion'; is_deeply [$context->ctxtFor(__('a{b 'en' , {gender => 'female', style => 'informal'})] , [ 'a{b%2f}c', 'gender=female style=informal' ]; is_deeply [$context->expand('{ 'en')] , [ 'a', [ 'gender2=female', 'gender2=male' ] ] , 'deeper gender2 alternatives'; is_deeply [$context->ctxtFor(__('{ 'en', {gender2 => 'female'})] , [ 'a', "gender2=female" ]; is_deeply [$context->expand('a{ctxtFor(__('a{ 'en', {gender3 => 'male'})] , [ 'a', "gender3=m1" ]; is_deeply [$context->ctxtFor(__('a{ 'en', {gender3 => 'unknown'})] , [ 'ax', "gender3=m1" ]; is_deeply [$context->expand('c{dctxtFor(__('c{d 'nl', {gender3 => 'unknown'})] , [ 'c{d}e', "gender3=x" ]; Log-Report-Lexicon-1.15/t/11ppiexp.t0000644000175000001440000000300514775703615017663 0ustar00markovusers00000000000000#!/usr/bin/env perl # Try Extract PPI use warnings; use strict; use File::Temp qw/tempdir/; use Test::More; use Log::Report 'my-domain'; use_ok 'Log::Report::Translator::POT'; BEGIN { eval "require PPI"; plan skip_all => 'PPI not installed' if $@; plan tests => 11; use_ok('Log::Report::Extract::PerlPPI'); } my $lexicon = tempdir CLEANUP => 1; #warn "Lexicon at $lexicon"; my $rules = { gender => [ 'male', 'female' ] , formal => [ 'informal', 'formal' ] }; my $domain = textdomain 'my-domain', context_rules => $rules; isa_ok $domain, 'Log::Report::Domain'; ### Create tables my $ppi = Log::Report::Extract::PerlPPI->new(lexicon => $lexicon); ok defined $ppi, 'created parser'; isa_ok $ppi, 'Log::Report::Extract::PerlPPI'; $ppi->process( __FILE__ ); # yes, this file! $ppi->write; #### my $old = textdomain 'my-domain', 'DELETE'; # restart administration isa_ok $old, 'Log::Report::Domain', 'caught deleted'; my $translator = Log::Report::Translator::POT->new(lexicon => $lexicon); my $new = textdomain 'my-domain' , context_rules => $rules , translator => $translator; isa_ok $new, 'Log::Report::Domain', 'recreated'; cmp_ok $old, '!=', $new, 'new is really new'; $new->setContext('gender=male,formal=informal'); my $a1 = __x"{name 'Mark'; is $a1, 'Mark forgot his key', 'Mark'; my $a2 = __xn"Dear Sir,{ 'here'; is $a3, 'no context here'; Log-Report-Lexicon-1.15/ChangeLog0000644000175000001440000001232215103071403017313 0ustar00markovusers00000000000000 ==== version history of Log::Report::Lexicon Unless noted otherwise, these changes where initiated and applied by Mark Overmeer. bugs: - with multiple domains extracted at once, remove references which appear in one PO but the file moved to other domain, not scanned in the same xgettext-perl run. - manual-page for xgettext-perl is missing - xgettext-perl does not yet support __*p* introduced by Log::Report version 1.22. It should probably accept variables as $msgctxt argument, to make code maintainable. wishlist: - let xgettext-perl produce mo files as well. version 1.15: Thu 6 Nov 11:05:27 CET 2025 Changes: - auto-detects (and applies) "use utf8", still not supported by PPI. Improvements: - remove double dependency on Test::More rt.cpan.org#171438 [Petr Pisar] - remove dependency on IO::File, not used rt.cpan.org#171438 [Petr Pisar] - better set locale in test script rt.cpan.org#171439 [Petr Pisar] - also accept perl scripts which do not end on .pl version 1.14: Mon 8 Sep 15:31:33 CEST 2025 Changes: - require Perl 5.16 (2012) Fixes: - fix pod2usage github merge#3 [Sam Kington] - understand 'use Log::Report' with minimal required version number github merge#4 and #5 [Sam Kington] Improvements: - convert to OODoc 3.03 version 1.13: Tue 6 May 09:49:55 CEST 2025 Changes: - move Log::Report::Extract::Template to Log::Report::Template::Extract.pm in distribution Log-Report-Template. Fixes: - --no-cleanup option was broken. Improvements: - ::Extract::write() passes options to ::Lexicon writers. version 1.12: Fri 18 Apr 17:10:11 CEST 2025 Fixes: - binmode for POTcompact - confusion between option name 'lexicon' or 'lexicons', accept both. - find gmo files. - no translations for the declaration of the conversion routines in Log::Report Improvements: - add .gitignore - add translation table - extract Template understand FILTER version 1.11: Thu Mar 22 23:32:11 CET 2018 Release 1.10 seems to got lost on CPAN. Upload a new one. Fixes: - fix metadata [Mohammad S Anwar] - $fh->binmode not supported before 5.12 [cpantesters] version 1.10: Tue Jan 23 23:03:57 CET 2018 Improvements: - typo, rt.cpan.org#123008 [Lukas Mai] - additional filename test in 30index.t - add debugging of fn0 to t/30index.t - convert to GIT - publish on GitHUB version 1.09: Mon 28 Aug 10:37:30 CEST 2017 Fixes: - support PO-table charsets only available in the file's header Reported by [Lars Dɪᴇᴄᴋᴏᴡ] Improvements: - do not require Plural-Forms in the header when it is not used. - remove option Log::Report::Lexicon::MOTcompact::read(take_all) Always take all, don't be smart (because it wasn't efficient at all) - support filename extension .gmo as alternative to .mo - ::Lexicon::POT::new(charset) from required to default 'UTF-8' version 1.08: Thu 29 Jun 15:02:15 CEST 2017 Fixes: - textdomain() from package. version 1.07: Tue 27 Jun 16:43:28 CEST 2017 Changes: - interpolated context values require "_context." prefix Fixes: - Accept END with blanks around it in piped syntax. Improvements: - spell-fix rt.cpan.org#118560 [Gregor Herrmann, Debian] - receive lexicon specific code from Log::Report::Translator (part of the Log::Report distribution) - warn when the msgid contains html-encoded characters, while extracting msgids from HTML. version 1.06: Wed 21 Sep 17:10:58 CEST 2016 Fixes: - extract __nx as well. Improvements: - take domain from Dancer2::Plugin::LogReport as well [Andy Beverley] version 1.05: Tue 12 Apr 15:09:32 CEST 2016 Fixes: - charset in MO files. [Paulo A Ferreira] Improvements: - explain context settings for interpolation (new in Log::Report 1.10) - explain relation to gettext's pgettext() command. - added --no-cleanup to bin/xgettext-perl - some documentation for bin/xgettext-perl version 1.04: Mon Jun 15 17:34:38 CEST 2015 Improvements: - spell-fix rt.cpan.org#96465 [Gregor Herrmann, Debian] - add Log::Report::Extract::addPot() version 1.03: Wed Jun 4 17:22:19 CEST 2014 Fixes: - more than one po-file with contexts. Reported by [Richard Still] Improvements: - accept PO-files which have CRLF endings, while running on LF platform (UNIX/Linux) version 1.02: Mon Mar 10 16:08:59 CET 2014 Changes: - ::PO::unused() -> ::PO::useless() Fixes: - do not run t/12ctxt.t on openbsd: that platform does not support LC_ALL [cpantesters] - ::POT::write(only_active) was not documented and only partially implemented [Patrick Goldmann] - ::POT::write() did not check the number of plural forms. [Patrick Goldmann] Improvements: - changed documentation style - explain how to use templates in combination with translation contexts version 1.01: Mon Jan 6 22:42:22 CET 2014 Fixes: - t/12ctxt.t failed when 'en' locale was not installed. Patched by [Slaven Rezic] version 1.00: Sun Jan 5 17:30:43 CET 2014 Split-off from Log::Report Fixes: - remove references to files which have disappeared from the set. Improvements: - add ::Lexicon as main extry point - add ::Translator::Context and smart support for msgctxt - command-line parameter option in xgettext-perl - add msgctxt support to tables maintained in POT, POTcompact, and MOcompact format. - more documentation Log-Report-Lexicon-1.15/Makefile.PL0000644000175000001440000000475615103070611017527 0ustar00markovusers00000000000000use ExtUtils::MakeMaker; use 5.016; # Use command 'oodist' to produce your whole software release. my $version = '1.15'; my $git = "https://github.com/markov2/perl5-Log-Report-Lexicon"; my $publish = "../public_html/log-report-lexicon"; my $homepage = "http://perl.overmeer.net/CPAN/"; my %oodist = ( oodoc_version => 3.03, first_year => 2007, email => "markov\@cpan.org", include => [ '../String-Print', '../Log-Report-Optional', ], use => [ '../Log-Report', '../Log-Report-Template', ], parser => { syntax => 'markov', skip_links => [ 'Locale::PO', 'Win32::Locale', 'Win32::Codepage', ], pmhead => undef, }, tests => { }, release => { publish => "$publish/source", }, raw => { publish => "$publish/raw", }, generate => [ { # Add real pod to the releases format => 'pod3', podtail => undef, }, # You may add HTML formatters here. # You may add exporter configurations here. ], ); my %prereq = ( 'Data::Dumper' => 0, 'Fcntl' => 0, 'File::Basename' => 0, 'File::Find' => 0, 'File::Spec' => 0, 'File::Temp' => 0, 'List::Util' => 0, 'Scalar::Util' => 0, 'Log::Report' => 1.40, 'Pod::Usage' => 0, 'POSIX' => 0, 'Encode' => 0, # sometimes needed, dependencies too large # PPI # Locale::gettext ); $prereq{ 'Win32::TieRegistry' } = 0.24 if $^O eq 'MSWin32'; WriteMakefile NAME => 'Log::Report::Lexicon', VERSION => $version, PREREQ_PM => \%prereq, EXE_FILES => [ 'bin/xgettext-perl' ], AUTHOR => 'Mark Overmeer ', ABSTRACT => 'Log::Report translation table management', LICENSE => 'perl_5', META_MERGE => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', url => "$git.git", web => $git, }, homepage => $homepage, license => [ 'http//dev.perl.org/licenses/' ], }, prereqs => { develop => { requires => { 'OODoc' => '3.00', } }, test => { requires => { 'Test::More' => 1.00, 'Test::Pod' => 1.00, } }, }, # You may use multiple set-ups, see "oodist --make" x_oodist => \%oodist, }; sub MY::postamble { <<'__POSTAMBLE' } # for translation tables messages:: bin/xgettext-perl --mode=VERBOSE -p lib/Log/Report/messages lib bin __POSTAMBLE Log-Report-Lexicon-1.15/xt/0000755000175000001440000000000015103071406016177 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/xt/99pod.t0000644000175000001440000000041614775703615017353 0ustar00markovusers00000000000000#!/usr/bin/env perl use warnings; use strict; use Test::More; BEGIN { eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; plan skip_all => "devel home uses OODoc" if $ENV{MARKOV_DEVEL}; } all_pod_files_ok(); Log-Report-Lexicon-1.15/README.txt0000644000175000001440000000164715057554660017272 0ustar00markovusers00000000000000=== README for Log-Report-Lexicon version 1.14 = Generated on Mon Sep 8 15:27:12 2025 by OODoc 3.04 There are various ways to install this module: (1) if you have a command-line, you can do: cpan -i ' (2) if you use Windows, have a look at https://strawberryperl.com (3) if you have downloaded this module manually (as root/administrator) tar -xzf Log-Report-Lexicon-1.14.tar.gz cd Log-Report-Lexicon-1.14 perl Makefile.PL make # optional make test # optional make install References: * For usage, see the included manual-pages or https://metacpan.org/dist/Log-Report-Lexicon * This project has a website at http://perl.overmeer.net/CPAN/ * The source repository can be found at https://github.com/markov2/perl5-Log-Report-Lexicon * Please report issues via https://github.com/markov2/perl5-Log-Report-Lexicon/issues Log-Report-Lexicon-1.15/bin/0000755000175000001440000000000015103071406016314 5ustar00markovusers00000000000000Log-Report-Lexicon-1.15/bin/xgettext-perl0000644000175000001440000001442115103070401021047 0ustar00markovusers00000000000000#!/usr/bin/env perl # implements xgettext for Log::Report only, using Log::Report::Extract::PPI # Options like GNU's xgettext use warnings; use strict; use Log::Report 'log-report-lexicon'; use Getopt::Long qw/:config no_ignore_case bundling/; use File::Find qw/find/; use Pod::Usage qw/pod2usage/; my $mode = 0; GetOptions 'cleanup!' => \(my $cleanup = 1), # kill transl from removed files, def true 'config|c=s' => \(my %configs), # domain configurations 'domain|d=s' => \(my $default_domain), # for templates 'files-from|f=s' => \(my $from), # file with filenames (MANIFEST?) or '-' 'files-match|m=s' => \(my $fn_match), # select filename is dir 'from-code=s' => \(my $char_in), 'help|h' => \(my $help = 0), 'language|L=s' => \(my $lang = 'perl'), 'mode=s' => \$mode, 'output-dir|p=s' => \(my $output), 'template|t=s' => \(my $template), # pattern in ::Template 'to-code=s' => \(my $char_out = 'utf-8'), # missing in xgettext? 'verbose=i' => \$mode, 'version|V' => \(my $version = 0), 'v+' => \$mode, or exit 1; if($version) { print "Log::Report $Log::Report::VERSION\n"; exit 0; } $help && pod2usage(0); # Load domain information, for instance defining context_rules. The # definitions are global, so automatically find their way in the Log::Report # internals. # --config domain1=filename domain2=filename # --config domain1=filename --config domain2=filename while(my ($domain, $fn) = each %configs) { trace "configuring domain $domain from $fn"; textdomain $domain, config => $fn; } # all output to stderr dispatcher FILE => stderr => to => \*STDERR , mode => $mode, format => sub {shift}; dispatcher close => 'default'; $template || $lang eq 'perl' or error __x"programming language {lang} not supported", lang => $lang; defined $output or error __"explicit output directory (-p) required"; -d $output or mkdir $output or fault __x"cannot create output directory {dir}", dir => $output; my @filenames; if(defined $from) { !@ARGV or error __x"do not combine command-line filenames with --files-from"; if($from eq '-') { @filenames = ; } else { open FILENAMES, '<:raw', $from or fault __x"cannot read filename list from {fn}", fn => $from; @filenames = ; close FILENAMES; } chomp(@filenames); } elsif(@ARGV) { find sub { push @filenames, $File::Find::name if -f }, @ARGV; } else { error "give --files-from or directories to be processed"; } my $extr; my %processed; if($template) { # process from template toolkit eval "require Log::Report::Template::Extract"; panic $@ if $@; $default_domain or error __x"specify a text-domain (-d) for the templates"; $extr = Log::Report::Template::Extract->new( lexicon => $output, charset => $char_out, domain => $default_domain, pattern => $template, ); $fn_match ||= qr/\.tt2?$/i; foreach my $filename (@filenames) { unless($filename =~ $fn_match) { info __x"skipping (not a template) {fn}", fn => $filename; next; } $extr->process($filename, charset => $char_in); $processed{$filename}++; } } else { # process the pm files eval "require Log::Report::Extract::PerlPPI"; error $@ if $@; $extr = Log::Report::Extract::PerlPPI->new(lexicon => $output, charset => $char_out); $fn_match ||= qr/\.p[lm]$/i; foreach my $filename (@filenames) { if($filename !~ $fn_match) { open my ($fh), '<', $filename or warning(__x"skipping missing file {fn}", fn => $filename), next; $fh->getline =~ m!\bperl\b|\bperl[0-9]! or info(__x"skipping (not perl) {fn}", fn => $filename), next; $fh->close; } $extr->process($filename, charset => $char_in); $processed{$filename}++; } } $extr->cleanup(keep => \%processed) if $cleanup; $extr->showStats; $extr->write; __END__ =head1 NAME xgettext-perl - extract translatable strings =head1 SYNOPSIS xgettext-perl [GENERIC OPTIONS][SCRIPT OPTIONS] directories xgettext-perl [GENERIC OPTIONS][TEMPLATE OPTIONS] directories GENERIC OPTIONS --config -c %config domain configuration --files-from -f $filename source of filenames to be processed --from-code $charset used by input files (auto-detects) --no-cleanup keep unprocessed files in po table --output-dir -p $directory location of lexicons (required) --to-code $charset charset of po files (default utf-8) --version -V show version of this script --verbose=3 -v -vv -vvv debug mode TEMPLATE OPTIONS --domain -d $domain domain to be used --template -t $notation how to recognize the strings to be taken --files-match -m $regex filter filenames, default .tt and .tt2 SCRIPT OPTIONS --language -L $proglang programming language syntax (now only perl) --files-match -m $regex filter filenames, default .pm and .pl =head1 DESCRIPTION This script will maintain PO-files: translation files. On the moment, the number of syntaxes is quite limited (see below) There is no restrain on syntaxes which can be supported: there just was no practical use to implement it yet. =head2 Complex options =over 4 =item --config %config Log::Report translations supports complex additional features, like context sensitive translations, which require a configuration file. See Log::Report::Context Say, your scripts and templates use textdomain name-spaces C and C (please use better names), then you can pass their respective configuration files as: --config domain1=filename domain2=filename # or --config domain1=filename --config domain2=filename =item --cleanup --no-cleanup You should scan all script or template files in one go, because PO records from files which are not mentioned will get removed. That's the clean-up. However, when you need more scans for a full update, you need to use this option. This also implies possible polution of your translation tables. =back =head2 Extracting from Perl with Log::Report syntax When no --template notation is given, the provided file-names are expected to contain program text. Only Perl5 programs using the Log::Report msgid notation (with leading '__' to mean gettext) =head2 Extracting from Template::Toolkit See Log::Report::Template::Extract =cut Log-Report-Lexicon-1.15/README0000644000175000001440000000150414775703616016447 0ustar00markovusers00000000000000=== README for Log-Report-Lexicon version 1.12 = Generated on Thu Apr 10 10:55:42 2025 by OODoc 2.03 There are various ways to install this module: (1) if you have a command-line, you can do: perl -MCPAN -e 'install ' (2) if you use Windows, have a look at http://ppm.activestate.com/ (3) if you have downloaded this module manually (as root/administrator) gzip -d Log-Report-Lexicon-1.12.tar.gz tar -xf Log-Report-Lexicon-1.12.tar cd Log-Report-Lexicon-1.12 perl Makefile.PL make # optional make test # optional make install For usage, see the included manual-pages or http://search.cpan.org/dist/Log-Report-Lexicon-1.12/ Please report problems to http://rt.cpan.org/Dist/Display.html?Queue=Log-Report-Lexicon Log-Report-Lexicon-1.15/MANIFEST0000644000175000001440000000323515103071407016701 0ustar00markovusers00000000000000ChangeLog MANIFEST Makefile.PL README README.txt bin/xgettext-perl lib/Log/Report/Extract.pm lib/Log/Report/Extract.pod lib/Log/Report/Extract/PerlPPI.pm lib/Log/Report/Extract/PerlPPI.pod lib/Log/Report/Extract/Template.pm lib/Log/Report/Extract/Template.pod lib/Log/Report/Lexicon.pm lib/Log/Report/Lexicon.pod lib/Log/Report/Lexicon/Index.pm lib/Log/Report/Lexicon/Index.pod lib/Log/Report/Lexicon/MOTcompact.pm lib/Log/Report/Lexicon/MOTcompact.pod lib/Log/Report/Lexicon/PO.pm lib/Log/Report/Lexicon/PO.pod lib/Log/Report/Lexicon/POT.pm lib/Log/Report/Lexicon/POT.pod lib/Log/Report/Lexicon/POTcompact.pm lib/Log/Report/Lexicon/POTcompact.pod lib/Log/Report/Lexicon/Table.pm lib/Log/Report/Lexicon/Table.pod lib/Log/Report/Translator/Context.pm lib/Log/Report/Translator/Context.pod lib/Log/Report/Translator/Gettext.pm lib/Log/Report/Translator/Gettext.pod lib/Log/Report/Translator/POT.pm lib/Log/Report/Translator/POT.pod lib/Log/Report/Win32Locale.pm lib/Log/Report/Win32Locale.pod lib/Log/Report/messages/log-report-lexicon/nl_NL.po t/00use.t t/04locale.t t/10context.t t/11ppiexp.t t/12ctxt.t t/12test/en_US.UTF-8.po t/20pot_read.t t/21pot_modif.t t/22compact.t t/30index.t t/40ppi.t t/41ppi_imports.t t/41templ.t t/hello-world-slovak.po t/simplecal/README t/simplecal/ar.po t/simplecal/ar_SA.mo t/simplecal/ar_SA.po t/simplecal/cs.po t/simplecal/de.po t/simplecal/de_AT.po t/simplecal/fr.po t/simplecal/ga.po t/simplecal/it.po t/simplecal/nl.po t/simplecal/pt.po t/simplecal/pt_BR.po t/simplecal/ru.po xt/99pod.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Log-Report-Lexicon-1.15/META.yml0000644000175000001440000000263215103071407017021 0ustar00markovusers00000000000000--- abstract: 'Log::Report translation table management' author: - 'Mark Overmeer ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '1' Test::Pod: '1' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Log-Report-Lexicon no_index: directory: - t - inc requires: Data::Dumper: '0' Encode: '0' Fcntl: '0' File::Basename: '0' File::Find: '0' File::Spec: '0' File::Temp: '0' List::Util: '0' Log::Report: '1.4' POSIX: '0' Pod::Usage: '0' Scalar::Util: '0' resources: homepage: http://perl.overmeer.net/CPAN/ repository: https://github.com/markov2/perl5-Log-Report-Lexicon.git version: '1.15' x_oodist: email: markov@cpan.org first_year: 2007 generate: - format: pod3 podtail: ~ include: - ../String-Print - ../Log-Report-Optional oodoc_version: 3.03 parser: pmhead: ~ skip_links: - Locale::PO - Win32::Locale - Win32::Codepage syntax: markov raw: publish: ../public_html/log-report-lexicon/raw release: publish: ../public_html/log-report-lexicon/source tests: {} use: - ../Log-Report - ../Log-Report-Template x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Log-Report-Lexicon-1.15/META.json0000644000175000001440000000505115103071407017167 0ustar00markovusers00000000000000{ "abstract" : "Log::Report translation table management", "author" : [ "Mark Overmeer " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Log-Report-Lexicon", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "OODoc" : "3.00" } }, "runtime" : { "requires" : { "Data::Dumper" : "0", "Encode" : "0", "Fcntl" : "0", "File::Basename" : "0", "File::Find" : "0", "File::Spec" : "0", "File::Temp" : "0", "List::Util" : "0", "Log::Report" : "1.4", "POSIX" : "0", "Pod::Usage" : "0", "Scalar::Util" : "0" } }, "test" : { "requires" : { "Test::More" : "1", "Test::Pod" : "1" } } }, "release_status" : "stable", "resources" : { "homepage" : "http://perl.overmeer.net/CPAN/", "repository" : { "type" : "git", "url" : "https://github.com/markov2/perl5-Log-Report-Lexicon.git", "web" : "https://github.com/markov2/perl5-Log-Report-Lexicon" } }, "version" : "1.15", "x_oodist" : { "email" : "markov@cpan.org", "first_year" : 2007, "generate" : [ { "format" : "pod3", "podtail" : null } ], "include" : [ "../String-Print", "../Log-Report-Optional" ], "oodoc_version" : 3.03, "parser" : { "pmhead" : null, "skip_links" : [ "Locale::PO", "Win32::Locale", "Win32::Codepage" ], "syntax" : "markov" }, "raw" : { "publish" : "../public_html/log-report-lexicon/raw" }, "release" : { "publish" : "../public_html/log-report-lexicon/source" }, "tests" : {}, "use" : [ "../Log-Report", "../Log-Report-Template" ] }, "x_serialization_backend" : "JSON::PP version 4.16" }