File Coverage

blib/lib/Locale/Utils/Autotranslator.pm
Criterion Covered Total %
statement 270 272 99.2
branch 90 116 77.5
condition 18 31 58.0
subroutine 44 44 100.0
pod 5 5 100.0
total 427 468 91.2


line stmt bran cond sub pod time code
1             package Locale::Utils::Autotranslator; ## no critic (TidyCode)
2            
3 10     10   213141 use strict;
  10         52  
  10         305  
4 10     10   71 use warnings;
  10         21  
  10         298  
5 10     10   55 use Carp qw(confess);
  10         20  
  10         487  
6 10     10   4226 use Encode qw(decode encode_utf8 find_encoding);
  10         120199  
  10         755  
7 10     10   5066 use Locale::PO;
  10         43096  
  10         383  
8 10     10   5131 use Locale::TextDomain::OO::Util::ExtractHeader;
  10         174517  
  10         319  
9 10     10   1612 use Moo;
  10         21347  
  10         75  
10 10     10   10620 use MooX::StrictConstructor;
  10         125743  
  10         63  
11 10     10   222220 use MooX::Types::MooseLike::Base qw(CodeRef Str);
  10         68078  
  10         964  
12 10     10   5030 use MooX::Types::MooseLike::Numeric qw(PositiveInt);
  10         14353  
  10         601  
13 10     10   87 use Try::Tiny;
  10         33  
  10         490  
14 10     10   64 use namespace::autoclean;
  10         22  
  10         84  
15            
16             our $VERSION = '1.016';
17            
18             # plural_ref e.g. ru
19             # The key is the plural form 0, 1 or 2.
20             # The value is the first number 0 .. that is resulting in that plural form.
21             # 0 => 1, # singular
22             # 1 => 2, # 2 .. 4 plural
23             # 2 => 5, # 5 .. plural
24             has _plural_ref => (
25             is => 'ro',
26             init_arg => undef,
27             default => sub { {} },
28             );
29            
30             sub _clear_plural_ref {
31 6     6   13 my $self = shift;
32            
33 6         26 %{ $self->_plural_ref } = ();
  6         40  
34            
35 6         14 return;
36             }
37            
38             # to store the original gettext parts by placeholder number
39             # e.g.
40             # %*(%1,singular,plural,zero)
41             # 1 => [ '*', 'singular', 'plural'. 'zero' ],
42             # %quant(%2,singular,plural)
43             # 2 => [ 'quant', 'singular', 'plural' ],
44             has _gettext_ref => (
45             is => 'ro',
46             init_arg => undef,
47             default => sub { {} },
48             );
49            
50             sub _clear_gettext_ref {
51 8     8   25 my $self = shift;
52            
53 8         19 %{ $self->_gettext_ref } = ();
  8         38  
54            
55 8         19 return;
56             }
57            
58             has _num_ref => (
59             is => 'ro',
60             init_arg => undef,
61             default => sub { {} },
62             );
63            
64             sub _clear_num_ref {
65 7     7   11 my $self = shift;
66            
67 7         13 %{ $self->_num_ref } = ();
  7         24  
68            
69 7         16 return;
70             }
71            
72             has error => (
73             is => 'rw',
74             init_arg => undef,
75             writer => '_error',
76             clearer => '_clear_error',
77             );
78            
79             has translation_count => (
80             is => 'rw',
81             init_arg => undef,
82             default => 0,
83             writer => '_translation_count',
84             );
85            
86             has item_translation_count => (
87             is => 'rw',
88             init_arg => undef,
89             default => 0,
90             writer => '_item_translation_count',
91             );
92            
93             sub _translation_count_increment {
94 27     27   47 my $self = shift;
95            
96 27         77 $self->_translation_count( $self->translation_count + 1 );
97            
98 27         47 return;
99             }
100            
101             sub _item_translation_count_increment {
102 34     34   56 my $self = shift;
103            
104 34         105 $self->_item_translation_count( $self->item_translation_count + 1 );
105            
106 34         59 return;
107             }
108            
109             has developer_language => (
110             is => 'ro',
111             isa => Str,
112             default => 'en',
113             );
114            
115             has language => (
116             is => 'ro',
117             isa => Str,
118             required => 1,
119             );
120            
121             has [ qw( before_translation_code after_translation_code ) ] => (
122             is => 'ro',
123             isa => CodeRef,
124             );
125            
126             has bytes_max => (
127             is => 'ro',
128             isa => PositiveInt,
129             );
130            
131             has comment => (
132             is => 'rw',
133             isa => Str,
134             clearer => '_clear_comment',
135             );
136            
137             # Coding schema:
138             # a .. w, z => A .. W, Z
139             # A .. W, Z => YA .. YW, YZ
140             # space => YX
141             # open, e.g. { => XX
142             # : => XY
143             # close, e.g. } => XZ
144             # other => XAA .. XPP
145             # like hex but
146             # 0123456789ABCDEF is
147             # ABCDEFGHIJKLMNOP
148             # not valid => XQ .. XW, YY
149            
150             my $encode_az = sub {
151             my $inner = shift;
152             local *__ANON__ = '$encode_az->'; ## no critic (InterpolationOfMetachars LocalVars)
153            
154             my $encode_inner = sub {
155             my ( $lc, $uc, $space, $colon, $other ) = @_;
156             local *__ANON__ = '$encode_inner->'; ## no critic (InterpolationOfMetachars LocalVars)
157            
158             defined $lc
159             and return uc $lc;
160             defined $uc
161             and return q{Y} . $uc;
162             defined $space
163             and return 'YX';
164             defined $colon
165             and return 'XY';
166            
167             $other = ord $other;
168             $other > 255 ## no critic (MagicNumbers)
169             and confess 'encode error Xnn overflow';
170             my $digit2 = int $other / 16; ## no critic (MagicNumbers)
171             my $digit1 = $other % 16; ## no critic (MagicNumbers)
172             for my $digit ( $digit2, $digit1 ) {
173             $digit = [ q{A} .. q{P} ]->[$digit];
174             }
175            
176             return q{X} . $digit2 . $digit1;
177             };
178            
179             $inner =~ s{
180             ( [a-wz] )
181             | ( [A-WZ] )
182             | ( [ ] )
183             | ( [:] )
184             | ( . )
185             }
186             {
187             $encode_inner->($1, $2, $3, $4, $5, $6)
188             }xmsge;
189            
190             return 'XX'. $inner . 'XZ';
191             };
192            
193 7     7   14 sub _encode_named_placeholder {
194             my ( $self, $placeholder ) = @_;
195            
196 7         47 ## no critic (EscapedMetacharacters)
197             $placeholder =~ s{
198             ( \\ \{ )
199             | \{ ( [^\{\}]* ) \}
200 7 50       32 }
201             {
202             $1
203             || $encode_az->($2)
204             }xmsge;
205 7         53 ## use critic (EscapedMetacharacters)
206            
207             return $placeholder;
208             }
209            
210             my $decode_inner = sub {
211             my $inner = shift;
212             local *__ANON__ = '$decode_inner->'; ## no critic (InterpolationOfMetachars LocalVars)
213            
214             my @chars = $inner =~ m{ (.) }xmsg;
215             my $decoded = q{};
216             CHAR:
217             while ( @chars ) {
218             my $char = shift @chars;
219             if ( $char =~ m{ \A [A-WZ] \z }xms ) {
220             $decoded .= lc $char;
221             next CHAR;
222             }
223             if ( $char eq q{Y} ) {
224             @chars
225             or return "DECODE_ERROR_Y($inner)";
226             my $char2 = shift @chars;
227             $decoded .= $char2 eq q{X}
228             ? q{ }
229             : uc $char2;
230             next CHAR;
231             }
232             if ( $char eq q{X} ) {
233             @chars
234             or return "DECODE_ERROR_Xn($inner)";
235             my $char2 = shift @chars;
236             if ( $char2 eq q{Y} ) {
237             $decoded .= q{:};
238             next CHAR;
239             }
240             @chars
241             or return "DECODE_ERROR_Xnn($inner)";
242             my $char3 = shift @chars;
243             my $decode_string = 'ABCDEFGHIJKLMNOP';
244             my $index2 = index $decode_string, $char2;
245             $index2 == -1 ## no critic (MagicNumbers)
246             and return "DECODE_ERROR_X?($inner)";
247             my $index1 = index $decode_string, $char3;
248             $index1 == -1 ## no critic (MagicNumbers)
249             and return "DECODE_ERROR_Xn?($inner)";
250             $decoded .= chr $index2 * 16 + $index1; ## no critic (MagicNumbers)
251             next CHAR;
252             }
253             return "DECODE_ERROR($inner)";
254             }
255            
256             return $decoded;
257             };
258 6     6   14
259             sub _decode_named_placeholder {
260 6         26 my ( $self, $placeholder ) = @_;
261            
262             $placeholder =~ s{
263             XX
264             ( [[:upper:]]+ )
265 3         7 XZ
266             }
267             {
268 6         16 q[{] . $decode_inner->($1) . q[}]
269             }xmsge;
270            
271             return $placeholder;
272 2     2   4 }
273            
274 2 50       10 sub _prepare_plural {
275             my ( $self, $nplurals, $plural_code ) = @_;
276            
277             exists $self->_plural_ref->{0}
278             and return;
279 2         5
280 4         102 ## no critic (MagicNumbers)
281 4 50       30 NUMBER:
282 0         0 for ( 0 .. 1000 ) {
283             my $plural = $plural_code->($_);
284             if ( $plural > ( $nplurals - 1 ) ) {
285             confess sprintf
286             'Using plural formula with value %s. Got index %s. nplurals is %s. Then the maximal expected index is %s',
287             $_,
288             $plural,
289 4 50       16 $nplurals,
290 4         10 $nplurals - 1;
291             }
292 4 100       18 if ( ! exists $self->_plural_ref->{$plural} ) {
  4         41  
293             $self->_plural_ref->{$plural} = $_;
294             }
295             $nplurals == ( keys %{ $self->_plural_ref } )
296             and last NUMBER;
297 2         5 }
298             ## use critic (MagicNumbers)
299            
300             return;
301 6     6 1 714 }
302            
303 6 50       26 sub translate { ## no critic (ExcessComplexity)
304             my ( $self, $name_read, $name_write ) = @_;
305 6 50       19
306             defined $name_read
307 6 50       50 or confess 'Undef is not a name of a po/pot file';
308             defined $name_write
309             or confess 'Undef is not a name of a po file';
310 6   33     10253 my $pos_ref = Locale::PO->load_file_asarray($name_read)
311             or confess "$name_read is not a valid po/pot file";
312            
313             my $header = Locale::TextDomain::OO::Util::ExtractHeader
314             ->instance
315             ->extract_header_msgstr(
316             Locale::PO->dequote(
317             $pos_ref->[0]->msgstr
318 6         3210 || confess "No header found in file $name_read",
319 6         36 ),
320 6         1017 );
321 6         15 my $charset = $header->{charset};
322 6         145 my $encode_obj = find_encoding($charset);
323 6         57 my $nplurals = $header->{nplurals};
324 6         14 my $plural_code = $header->{plural_code};
325             $self->_clear_error;
326 6         69 $self->_clear_plural_ref;
327 6         29 my $entry_ref = { encode_obj => $encode_obj };
328            
329             $self->_translation_count(0);
330 6     6   322 $self->_item_translation_count(0);
  6         16  
  6         17  
331 15         323 try {
332             MESSAGE:
333 15   33     101 for my $po ( @{$pos_ref}[ 1 .. $#{$pos_ref} ] ) { # without 0 = header
334             $self->_clear_comment;
335             $entry_ref->{msgid}
336 15   66     626 = $po->msgid
337             && $encode_obj->decode( $po->dequote( $po->msgid ) );
338             $entry_ref->{msgid_plural}
339 15   66     202 = defined $po->msgid_plural
340             && $encode_obj->decode( $po->dequote( $po->msgid_plural ) );
341             $entry_ref->{msgstr}
342 15 50       391 = defined $po->msgstr
343 15         38 && $po->dequote( $po->msgstr );
344 15   100     59 length $entry_ref->{msgstr}
345 15         141 and next MESSAGE;
346 15         51 $entry_ref->{msgstr_n} = {};
347             my $msgstr_n = $po->msgstr_n || {};
348             my $is_all_translated = 1;
349 30   66     109 for my $index ( 0 .. ( $nplurals - 1 ) ) {
350             $entry_ref->{msgstr_n}->{$index}
351             = defined $msgstr_n->{$index}
352 30   33     172 && $po->dequote( $msgstr_n->{$index} );
353 30   66     101 my $is_translated
354             = defined $entry_ref->{msgstr_n}->{$index}
355             && length $entry_ref->{msgstr_n}->{$index};
356 15 50       35 $is_all_translated &&= $is_translated;
357 15 100       127 }
    100          
    100          
358 2 50       7 $is_all_translated
359 2         11 and next MESSAGE;
360             if ( length $entry_ref->{msgid_plural} ) {
361 2         11 if ( $nplurals ) {
362             $self->_prepare_plural($nplurals, $plural_code);
363             }
364             $self->_translate_named_plural($entry_ref, $po);
365 3         29 }
366             ## no critic (EscapedMetacharacters)
367             elsif ( $entry_ref->{msgid} =~ m{ \{ [^\{\}]+ \} }xms ) {
368             $self->_translate_named($entry_ref, $po);
369 8         42 }
370             ## use critic (EscapedMetacharacters)
371             elsif ( $entry_ref->{msgid} =~ m{ [%] (?: \d | [*] | quant ) }xms ) {
372 2         13 $self->_translate_gettext($entry_ref, $po);
373             }
374 11         36 else {
375             $self->_translate_simple($entry_ref, $po);
376 2 50       16 }
377 2         10 $self->_update_comment($po);
378             }
379             if ( $self->translation_count ) {
380             Locale::PO->save_file_fromarray($name_write, $pos_ref);
381 4 100   4   3032 }
382 2         10 }
383             catch {
384             if ( $self->translation_count ) {
385             Locale::PO->save_file_fromarray($name_write, $pos_ref);
386             }
387             ## no critic (ComplexRegexes)
388             m{
389             \A \QAPI error: \E
390             |
391             \A \QByte limit exceeded, \E
392             |
393 4 50       2455 \A (?: Before | After )
394             (?: \Q paragraph\E | \Q line\E )?
395 6         58 \Q translation break\E \b
396             }xms or confess $_;
397 6         2692 ## use critic (ComplexRegexes)
398             };
399            
400             return $self;
401 7     7   19 }
402            
403 7 100       22 sub _encode_named {
404 7         26 my ( $self, $msgid, $num ) = @_;
405            
406 14     14   44 $num = defined $num ? $num : 1;
407 14         57 $self->_clear_num_ref;
408 14 100       35 my $encode_placeholder = sub {
409 7         26 my ( $placeholder, $is_num ) = @_;
410 7         44 local *__ANON__ = '$encode_placeholder->'; ## no critic (InterpolationOfMetachars LocalVars)
411             if ( $is_num ) {
412 7         25 $self->_num_ref->{$num} = $placeholder;
413 7         39 return $num++;
414             }
415 7         58 return $self->_encode_named_placeholder($placeholder);
416             };
417             ## no critic (EscapedMetacharacters)
418             $msgid =~ s{
419             ( \\ \{ )
420             | (
421             \{
422             [^\{\}:]+
423             ( [:] ( num )? [^\{\}]* )?
424 14 50       76 \}
425             )
426             }
427             {
428             $1
429 7         37 || $encode_placeholder->($2, $3)
430             }xmsge;
431             ## use critic (EscapedMetacharacters)
432            
433 6     6   12 return $msgid;
434             }
435 6         31
436 6 100       38 sub _decode_named {
437             my ( $self, $msgstr ) = @_;
438 6         38
439             $msgstr =~ s{ ( \d+ ) }{
440 6         15 exists $self->_num_ref->{$1} ? $self->_num_ref->{$1} : $1
441             }xmsge;
442             $msgstr = $self->_decode_named_placeholder($msgstr);
443            
444 3     3   10 return $msgstr;
445             }
446 3         40
447 3         32 sub _translate_named {
448 2         11 my ( $self, $entry_ref, $po ) = @_;
449 2         14
450             my $msgid = $self->_encode_named( $entry_ref->{msgid} );
451 2         32 my $msgstr = $self->translate_any_msgid($msgid, 1);
452             $msgstr = $self->_decode_named($msgstr);
453             $po->msgstr( $entry_ref->{encode_obj}->encode($msgstr) );
454            
455 2     2   6 return;
456             }
457 2         15
458 2         5 sub _translate_named_plural {
459             my ( $self, $entry_ref, $po ) = @_;
460 2         4
  2         12  
461             my $msgid = $entry_ref->{msgid};
462 4 50 33     58 my $msgid_plural = $entry_ref->{msgid_plural};
463             MSGSTR_N:
464             for my $index ( sort keys %{ $self->_plural_ref } ) {
465             defined $entry_ref->{msgstr_n}->{$index}
466 4 100       32 and length $entry_ref->{msgstr_n}->{$index}
467             and next MSGSTR_N;
468             my $any_msgid = $self->_encode_named(
469 4         11 $index
470 4         11 ? ( $msgid_plural, $self->_plural_ref->{$index} )
471             : $msgid,
472 4         23 );
473             my $any_msgstr = $self->translate_any_msgid($any_msgid, 1);
474             $any_msgstr = $self->_decode_named($any_msgstr);
475 2         35 $po->msgstr_n->{$index}
476             = $po->quote( $entry_ref->{encode_obj}->encode($any_msgstr) );
477             }
478            
479 6     6   30 return;
480             }
481            
482             sub _encode_gettext_inner { ## no critic (ManyArgs)
483 6   100     40 my ( $self, $quant, $number, $inner, $singular, $plural, $zero ) = @_;
484 12 100 66     67
485             $self->_gettext_ref->{$inner} ||= [
486             map {
487             ( defined && length )
488             ? $self->translate_any_msgid($_, 1)
489 6         24 : undef;
490             } $singular, $plural, $zero
491             ];
492            
493 8     8   18 return $encode_az->("$quant,$number,$inner");
494             }
495            
496 8         69 sub _encode_gettext {
497             my ( $self, $msgid ) = @_;
498            
499             ## no critic (ComplexRegexes)
500             $msgid =~ s{
501             ( %% ) # escaped
502             |
503             [%] ( [*] | quant ) [(] # quant
504             [%] ( \d+ ) [,] # number
505             ( # inner
506             ( [^,)]* ) # singular
507             [,] ( [^,)]* ) # plural
508             (?: [,] ( [^,)]* ) )? # zero
509             )
510 20 100       134 [)]
    50          
511             |
512             [%] ( \d+ ) # simple
513             }
514             {
515             $1
516             ? $1
517             : $2
518 8         28 ? $self->_encode_gettext_inner($2, $3, $4, $5, $6, $7)
519             : $encode_az->($8)
520             }xmsge;
521             ## use critic (ComplexRegexes)
522 8     8   22
523             return $msgid;
524 8         18 }
525 8 100       30
526 5         31 sub _decode_gettext_inner {
527             my ( $self, $inner ) = @_;
528 3 50       12
529 3         14 $inner = $decode_inner->($inner);
530             if ( $inner =~ m{ \A ( \d+ ) \z }xms ) {
531             return q{%} . $1;
532             }
533             if ( $inner =~ m{ \A ( [*] | quant ) [,] ( \d+ ) [,] ( .* ) \z }xms ) {
534 3         7 my ( $quant, $number, $plural ) = ( $1, $2, $self->_gettext_ref->{$3} );
  9         33  
  3         7  
535             return join q{},
536             q{%},
537             $quant,
538 0         0 q{(},
539             ( join q{,}, "%$number", grep { defined } @{$plural}[ 0 .. 2 ] ),
540             q{)};
541             }
542 5     5   12
543             return "DECODE_ERROR($inner)";
544 5         30 }
545            
546             sub _decode_gettext {
547             my ( $self, $msgstr ) = @_;
548            
549 8         23 $msgstr =~ s{
550             XX
551             ( [[:upper:]]+? )
552 5         14 XZ
553             }
554             {
555             $self->_decode_gettext_inner($1)
556 8     8   20 }xmsge;
557            
558 8         40 return $msgstr;
559 8         29 }
560 8         46
561 5         19 sub _translate_gettext {
562 5         49 my ( $self, $entry_ref, $po ) = @_;
563            
564 5         95 $self->_clear_gettext_ref;
565             my $msgid = $self->_encode_gettext( $entry_ref->{msgid} );
566             my $msgstr = $self->translate_any_msgid($msgid, 1);
567             $msgstr = $self->_decode_gettext($msgstr);
568 2     2   5 $po->msgstr( $entry_ref->{encode_obj}->encode($msgstr) );
569            
570             return;
571             }
572 2         7
573             sub _translate_simple {
574             my ( $self, $entry_ref, $po ) = @_;
575            
576 2         33 $po->msgstr(
577             $entry_ref->{encode_obj}->encode(
578             $self->translate_any_msgid( $entry_ref->{msgid}, 1 ),
579             ),
580 11     11   30 );
581            
582 11 100       262 return;
583             }
584 6 50       145
585             sub _update_comment {
586 6 100       47 my ( $self, $po ) = @_;
587 5         103
588 5         52 defined $self->comment
589             or return;
590             length $self->comment
591             or return;
592 1         7 if ( ! defined $po->comment ) {
  2         43  
593             $po->comment( $self->comment );
594             return;
595 1         22 }
596             my @lines
597 1         13 = grep {
598             $_ ne $self->comment;
599             }
600             $po->comment =~ m{ [\n]* ( [^\n]+ ) }xmsg;
601 6     6 1 109 $po->comment( join "\n", $self->comment, @lines );
602            
603 6 50       18 return;
604             }
605 6 50       15
606             sub with_paragraphs {
607             my ( $self, $msgid, $callback ) = @_;
608 6         25
609 6         10 ref $callback eq 'CODE'
610             or confess 'Code reference expected';
611             defined $msgid
612             or return $msgid;
613 12         45
614             my $has_network_line_endings = $msgid =~ s{ \r\n }{\n}xmsg;
615 13 100       51 my ( @prefix, @suffix );
616             my $msgstr
617 6         49 = join "\n\n",
  13         24  
618 13         46 map {
  13         35  
  13         36  
619 13         86 ( shift @prefix ) . $_ . ( shift @suffix );
  13         29  
  13         30  
620 13         39 }
621             map { length $_ ? $callback->($_) : $_ }
622             map { ## no critic (ComplexMappings)
623 5 100       24 my $paragraph = $_;
624             $paragraph =~ s{ \A ( \s* ) }{ push @prefix, $1; q{} }xmse; # left
625             $paragraph =~ s{ ( \s* ) \z }{ push @suffix, $1; q{} }xmse; # right
626 5         25 $paragraph;
627             }
628             split m{ \n [^\S\n]* \n }xms, $msgid;
629             $has_network_line_endings
630 6     6 1 95 and $msgstr =~ s{ \n }{\r\n}xmsg;
631            
632 6 50       32 return $msgstr;
633             }
634 6 50       17
635             sub with_lines {
636             my ( $self, $msgid, $callback ) = @_;
637 6         23
638 6         10 ref $callback eq 'CODE'
639             or confess 'Code reference expected';
640             defined $msgid
641             or return $msgid;
642            
643 14         64 my $has_network_line_endings = $msgid =~ s{ \r\n }{\n}xmsg;
644             my ( @prefix, @suffix );
645 15 100       52
646             return
647 6 100       27 join $has_network_line_endings ? ( "\r\n" ) : ( "\n" ),
  15         25  
648 15         53 map {
  15         36  
  15         34  
649 15         81 ( shift @prefix ) . $_ . ( shift @suffix );
  15         37  
  15         29  
650 15         40 }
651 15         40 map { length $_ ? $callback->($_) : $_ }
652             map { ## no critic (ComplexMappings)
653             my $line = $_;
654             $line =~ s{ \A ( \s* ) }{ push @prefix, $1; q{} }xmse; # left
655             $line =~ s{ ( \s* ) \z }{ push @suffix, $1; q{} }xmse; # right
656             $line =~ s{ \s+ }{ }xmsg; # inner
657 71     71   130 $line;
658             }
659 71 100       245 split m{ \n }xms, $msgid;
660             }
661 19         56
662             sub _bytes_max_fail_message {
663             my ( $self, $msgid ) = @_;
664 19 100       55
665 9         34 $self->bytes_max
666 9         45 or return 0;
667             my $msgid_bytes = length encode_utf8($msgid);
668            
669             return $msgid_bytes > $self->bytes_max
670             ? do {
671             ( my $msgid_short = $msgid ) =~ s{ \A ( .{80} ) .* \z }{$1 ...}xms;
672 33     33   72 "Byte limit exceeded, $msgid_bytes bytes at: $msgid_short";
673             }
674             : q{};
675             }
676            
677             sub _translate_paragraph {
678 8     8   30 my ( $self, $msgid ) = @_;
679 8 100       37
680             return $self->_bytes_max_fail_message($msgid)
681 7         16 ? $self->with_lines(
682 7 50       38 $msgid,
683             sub {
684 7         16 my $fail_message = $self->_bytes_max_fail_message($_);
685 7         11 $fail_message
686 7 50       16 and die $fail_message, "\n";
687             my $msgstr = $self->translate_text($_);
688 7         17 defined $msgstr
689             or $msgstr = q{};
690             $self->_item_translation_count_increment;
691 33 100       70 $msgstr =~ s{ [\x{0}\x{4}] }{}xmsg; # because of mo file conflicts
692 29         94 length $msgstr
693 27 100       135 or die "No translation break\n";
694             return $msgstr;
695 27         117 },
696 27         71 )
697 27 100       88 : do {
698             my $msgstr = $self->translate_text($msgid);
699 26         85 defined $msgstr
700             or $msgstr = q{};
701             $self->_item_translation_count_increment;
702             $msgstr =~ s{ [\x{0}\x{4}] }{}xmsg; # because of mo file conflicts
703             length $msgstr
704 31     31 1 636 or die "No translation break\n";
705             $msgstr;
706 31 0       150 };
    50          
707             }
708            
709             sub translate_any_msgid {
710 31 100       91 my ( $self, $msgid, $is_called_indirectly ) = @_;
711 23 100       73
712             $self->error
713             and $is_called_indirectly
714 30         290 ? ( die $self->error, "\n" )
715             : return q{};
716             if ( $self->before_translation_code ) {
717             $self->before_translation_code->($self, $msgid)
718 7         16 or die "Before translation break\n";
719 30 100   30   1379 }
720             my $fail_message = $self->_bytes_max_fail_message($msgid);
721             my $msgstr
722 4 100   4   826 = try {
    100          
723             $fail_message
724             ? $self->with_paragraphs($msgid, sub { $self->_translate_paragraph($_) })
725             : $self->_translate_paragraph($msgid, 'is_not_paragraph');
726 1         4 }
727 1         8 catch {
728             if ( m{ \A \QNo translation break\E \b }xms ) {
729             ;
730 2         28 }
731             elsif ( m{ \A \QByte limit exceeded, \E }xms ) {
732 4         22 chomp;
733 30         264 $self->_error($_);
734 30 100       499 }
    100          
735             else {
736             $self->_error("API error: $_")
737             }
738 27         82 q{};
739 27 100       77 };
740 24 100       68 $self->error
741             and $is_called_indirectly
742             ? ( die $self->error, "\n" )
743             : return q{};
744 26         312 $self->_translation_count_increment;
745             if ( $self->after_translation_code ) {
746             $self->after_translation_code->($self, $msgid, $msgstr)
747             or die "After translation break\n";
748 1     1 1 3 }
749            
750 1         2 return $msgstr;
751             }
752            
753             sub translate_text {
754             my ( $self, $msgid ) = @_;
755            
756             return;
757             }
758            
759             __PACKAGE__->meta->make_immutable;
760            
761             1;
762            
763             __END__