File Coverage

blib/lib/Locale/TextDomain/OO/Extract/Process/Plugin/PO.pm
Criterion Covered Total %
statement 33 114 28.9
branch 0 50 0.0
condition 0 6 0.0
subroutine 11 18 61.1
pod 4 4 100.0
total 48 192 25.0


line stmt bran cond sub pod time code
1             package Locale::TextDomain::OO::Extract::Process::Plugin::PO; ## no critic (TidyCode)
2            
3 1     1   4404 use strict;
  1         2  
  1         25  
4 1     1   29 use warnings;
  1         2  
  1         30  
5 1     1   5 use Carp qw(confess);
  1         2  
  1         44  
6 1     1   5 use Encode qw(find_encoding);
  1         2  
  1         34  
7 1     1   291 use Locale::PO;
  1         2976  
  1         29  
8 1     1   6 use Locale::TextDomain::OO::Util::ExtractHeader;
  1         2  
  1         19  
9 1     1   5 use Locale::TextDomain::OO::Util::JoinSplitLexiconKeys;
  1         2  
  1         15  
10 1     1   5 use Moo;
  1         2  
  1         5  
11 1     1   262 use MooX::StrictConstructor;
  1         2  
  1         6  
12 1     1   691 use MooX::Types::MooseLike::Base qw(HashRef Str);
  1         2  
  1         48  
13 1     1   7 use namespace::autoclean;
  1         1  
  1         6  
14            
15             our $VERSION = '2.007';
16            
17             has category => (
18             is => 'rw',
19             isa => Str,
20             lazy => 1,
21             default => q{},
22             );
23            
24             has domain => (
25             is => 'rw',
26             isa => Str,
27             lazy => 1,
28             default => q{},
29             );
30            
31             has language => (
32             is => 'rw',
33             isa => Str,
34             lazy => 1,
35             default => 'i-default',
36             );
37            
38             has project => (
39             is => 'rw',
40             isa => sub {
41             my $project = shift;
42             defined $project
43             or return;
44             return Str->($project);
45             },
46             );
47            
48             has lexicon_ref => (
49             is => 'rw',
50             isa => HashRef,
51             lazy => 1,
52             default => sub { {} },
53             );
54            
55             sub clear {
56 0     0 1   my $self = shift;
57            
58 0           $self->category( q{} );
59 0           $self->domain( q{} );
60 0           $self->language('i-default');
61 0           $self->project(undef);
62 0           $self->lexicon_ref( {} );
63            
64 0           return;
65             }
66            
67             sub slurp {
68 0     0 1   my ( $self, $filename ) = @_;
69            
70 0 0         defined $filename
71             or confess 'Undef is not a name of a po/pot file';
72 0 0         my $pos_ref = Locale::PO->load_file_asarray($filename)
73             or confess "$filename is not a valid po/pot file";
74            
75 0   0       my $header = Locale::TextDomain::OO::Util::ExtractHeader
76             ->instance
77             ->extract_header_msgstr(
78             Locale::PO->dequote(
79             $pos_ref->[0]->msgstr
80             || confess "No header found in file $filename",
81             ),
82             );
83 0           my $encode_obj = find_encoding( $header->{charset} );
84 0           my $nplurals = $header->{nplurals};
85 0           my $plural = $header->{plural};
86            
87             my $decode_code = sub {
88 0     0     my $text = shift;
89             #
90 0 0         defined $text
91             or return;
92 0 0         length $text
93             or return q{};
94             #
95 0           return $encode_obj->decode($text);
96 0           };
97             my $decode_dequote_code = sub {
98 0     0     my $text = shift;
99             #
100 0 0         defined $text
101             or return;
102 0           $text = Locale::PO->dequote($text);
103 0 0         length $text
104             or return;
105             #
106 0           return $encode_obj->decode($text);
107 0           };
108            
109 0           my $index = 0;
110 0           for my $po ( @{$pos_ref} ) {
  0            
111             my %entry_of = (
112             (
113             $index++
114             ? ()
115             : (
116             nplurals => $nplurals,
117             plural => $plural,
118             )
119             ),
120             (
121             map { ## no critic (ComplexMappings)
122 0           my $value = $decode_code->( $po->$_ );
123 0 0         defined $value
124             ? ( $_ => $value )
125             : ();
126             }
127             qw( automatic comment reference )
128             ),
129             (
130             map { ## no critic (ComplexMappings)
131 0           my $value = $decode_dequote_code->( $po->$_ );
132 0 0         defined $value
133             ? ( $_ => $value )
134             : ();
135             }
136             qw( msgctxt msgid msgid_plural )
137             ),
138             (
139             defined $po->msgid_plural
140             ? (
141             msgstr_plural => [
142             do {
143 0           my $msgstr_n = $po->msgstr_n;
144             map {
145 0           scalar $decode_dequote_code->( $msgstr_n->{$_} );
  0            
146             }
147             0 .. ( $nplurals - 1 );
148             },
149             ],
150             )
151 0 0         : do {
    0          
152 0           my $value = $decode_dequote_code->( $po->msgstr );
153 0 0         defined $value
154             ? ( msgstr => $value )
155             : ();
156             }
157             ),
158             );
159 0           my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
160 0           my $lexicon_key = $key_util->join_lexicon_key({
161             category => $self->category,
162             domain => $self->domain,
163             language => $self->language,
164             project => $self->project,
165             });
166 0           my ( $message_key, $message_value_ref )
167             = $key_util->split_message( \%entry_of );
168 0           $self->lexicon_ref->{$lexicon_key}->{$message_key} = $message_value_ref;
169             }
170            
171 0           return;
172             }
173            
174             sub default_header {
175 0     0 1   my ( $self, $language ) = @_;
176            
177 0           return <<"EOT";
178             msgid ""
179             msgstr ""
180             "Project-Id-Version: Default-Project 1.0\\n"
181             "PO-Revision-Date: 2000-01-01T00:00:00Z\\n"
182             "Last-Translator: first and last name \\n"
183             "Language-Team: LANGUAGE \\n"
184             "MIME-Version: 1.0\\n"
185             "Content-Type: text/plain; charset=UTF-8\\n"
186             "Content-Transfer-Encoding: 8bit\\n"
187             "Language: $language\\n"
188             "Plural-Forms: nplurals=2; plural=(n != 1);"
189            
190             EOT
191             }
192            
193             sub spew {
194 0     0 1   my ( $self, $filename ) = @_;
195            
196 0 0         defined $filename
197             or confess 'Undef is not a name of a po/pot file';
198            
199 0           my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
200 0           my $lexicon_key = $key_util
201             ->instance
202             ->join_lexicon_key({
203             category => $self->category,
204             domain => $self->domain,
205             language => $self->language,
206             project => $self->project,
207             });
208 0 0         my $entries_ref = $self->lexicon_ref->{$lexicon_key}
    0          
209             or confess sprintf
210             'No lexicon found for category "%s", domain "%s", language "%s" and project "%s"',
211             $self->category,
212             $self->domain,
213             $self->language,
214             ( defined $self->project ? $self->project : 'undef' );
215            
216             my $header = Locale::TextDomain::OO::Util::ExtractHeader
217             ->instance
218             ->extract_header_msgstr(
219             $entries_ref->{ q{} }->{msgstr}
220 0 0 0       || $self->default_header,
    0          
221             )
222             or confess sprintf
223             'No header found in lexicon of category "%s", domain "%s", language "%s" and project "%s"',
224             $self->category,
225             $self->domain,
226             $self->language,
227             ( defined $self->project ? $self->project : 'undef');
228 0           my $encode_obj = find_encoding( $header->{charset} );
229 0           my $nplurals = $header->{nplurals};
230            
231             my @po_data = map { ## no critic (ComplexMappings)
232 0           my $entry_ref = $key_util->join_message( $_, $entries_ref->{$_} );
233 0 0         if ( defined $entry_ref->{reference} ) {
234 0           my $reference_regex = qr{
235             \s*
236             (
237             ( [^:]+ )
238             [:]
239             ( \d+ )
240             )
241             }xms;
242             my @match = ref $entry_ref->{reference} eq 'HASH'
243             ? (
244             map {
245 0           $_ =~ $reference_regex;
246             }
247 0           keys %{ $entry_ref->{reference} }
248             )
249 0 0         : $entry_ref->{reference} =~ m{ $reference_regex }xmsg;
250 0           my @references;
251 0           while ( my ( $reference, $name, $line ) = splice @match, 0, 3 ) { ## no critic (MagicNumbers)
252 0           push @references, [ $reference, $name, $line ];
253             }
254             $entry_ref->{reference} = join "\n",
255 0           map { $_->[0] }
256 0 0         sort { $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] }
  0            
257             @references;
258             }
259 0           $entry_ref;
260             }
261             sort
262 0           keys %{$entries_ref};
  0            
263            
264             my $encode_code = sub {
265 0     0     my $text = shift;
266             #
267 0 0         defined $text
268             or return;
269 0 0         length $text
270             or return q{};
271             #
272 0           return $encode_obj->encode($text);
273 0           };
274             Locale::PO->save_file_fromarray(
275             $filename,
276             [
277             map { ## no critic (ComplexMappings)
278 0           my $po_data = $_;
  0            
279             Locale::PO->new(
280             (
281             map { ## no critic (ComplexMappings)
282 0           my $value = $po_data->{$_};
283 0 0         defined $value
284             ? ( "-$_" => scalar $encode_code->($value) )
285             : ();
286             }
287             qw( automatic comment msgctxt msgid msgid_plural reference )
288             ),
289             (
290             defined $po_data->{msgid_plural}
291             ? (
292             '-msgstr_n' => {
293             map { ## no critic (ComplexMappings)
294 0           my $value = $po_data->{msgstr_plural}->[$_];
295             (
296 0 0         $_ => scalar $encode_code->(
297             defined $value ? $value : q{},
298             ),
299             );
300             }
301             0 .. ( $nplurals - 1 )
302             },
303             )
304             : (
305             '-msgstr' => scalar $encode_code->(
306             defined $po_data->{msgstr}
307             ? $po_data->{msgstr}
308 0 0         : q{}
    0          
309             ),
310             )
311             ),
312             );
313             }
314             @po_data
315             ],
316             );
317            
318 0           return;
319             }
320            
321             __PACKAGE__->meta->make_immutable;
322            
323             1;
324            
325             __END__