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   205690 use strict;
  10         42  
  10         308  
4 10     10   63 use warnings;
  10         21  
  10         300  
5 10     10   53 use Carp qw(confess);
  10         22  
  10         553  
6 10     10   4190 use Encode qw(decode encode_utf8 find_encoding);
  10         120257  
  10         786  
7 10     10   5385 use Locale::PO;
  10         42743  
  10         378  
8 10     10   5404 use Locale::TextDomain::OO::Util::ExtractHeader;
  10         174975  
  10         322  
9 10     10   1560 use Moo;
  10         20847  
  10         78  
10 10     10   10619 use MooX::StrictConstructor;
  10         126024  
  10         105  
11 10     10   226824 use MooX::Types::MooseLike::Base qw(CodeRef Str);
  10         69296  
  10         978  
12 10     10   5298 use MooX::Types::MooseLike::Numeric qw(PositiveInt);
  10         14366  
  10         607  
13 10     10   78 use Try::Tiny;
  10         44  
  10         483  
14 10     10   70 use namespace::autoclean;
  10         21  
  10         90  
15            
16             our $VERSION = '1.015';
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   27 my $self = shift;
32            
33 6         12 %{ $self->_plural_ref } = ();
  6         41  
34            
35 6         15 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   17 my $self = shift;
52            
53 8         26 %{ $self->_gettext_ref } = ();
  8         41  
54            
55 8         20 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         12 %{ $self->_num_ref } = ();
  7         28  
68            
69 7         14 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   49 my $self = shift;
95            
96 27         95 $self->_translation_count( $self->translation_count + 1 );
97            
98 27         48 return;
99             }
100            
101             sub _item_translation_count_increment {
102 34     34   65 my $self = shift;
103            
104 34         119 $self->_item_translation_count( $self->item_translation_count + 1 );
105            
106 34         57 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         32 ## no critic (EscapedMetacharacters)
197             $placeholder =~ s{
198             ( \\ \{ )
199             | \{ ( [^\{\}]* ) \}
200 7 50       36 }
201             {
202             $1
203             || $encode_az->($2)
204             }xmsge;
205 7         54 ## 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   13
259             sub _decode_named_placeholder {
260 6         27 my ( $self, $placeholder ) = @_;
261            
262             $placeholder =~ s{
263             XX
264             ( [[:upper:]]+ )
265 3         7 XZ
266             }
267             {
268 6         15 q[{] . $decode_inner->($1) . q[}]
269             }xmsge;
270            
271             return $placeholder;
272 2     2   4 }
273            
274 2 50       9 sub _prepare_plural {
275             my ( $self, $nplurals, $plural_code ) = @_;
276            
277             exists $self->_plural_ref->{0}
278             and return;
279 2         5
280 4         104 ## 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       17 $nplurals,
290 4         21 $nplurals - 1;
291             }
292 4 100       12 if ( ! exists $self->_plural_ref->{$plural} ) {
  4         32  
293             $self->_plural_ref->{$plural} = $_;
294             }
295             $nplurals == ( keys %{ $self->_plural_ref } )
296             and last NUMBER;
297 2         4 }
298             ## use critic (MagicNumbers)
299            
300             return;
301 6     6 1 740 }
302            
303 6 50       26 sub translate { ## no critic (ExcessComplexity)
304             my ( $self, $name_read, $name_write ) = @_;
305 6 50       21
306             defined $name_read
307 6 50       53 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     10376 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         3486 || confess "No header found in file $name_read",
319 6         46 ),
320 6         1142 );
321 6         16 my $charset = $header->{charset};
322 6         161 my $encode_obj = find_encoding($charset);
323 6         58 my $nplurals = $header->{nplurals};
324 6         16 my $plural_code = $header->{plural_code};
325             $self->_clear_error;
326 6         37 $self->_clear_plural_ref;
327 6         27 my $entry_ref = { encode_obj => $encode_obj };
328            
329             $self->_translation_count(0);
330 6     6   345 $self->_item_translation_count(0);
  6         20  
  6         18  
331 15         328 try {
332             MESSAGE:
333 15   33     104 for my $po ( @{$pos_ref}[ 1 .. $#{$pos_ref} ] ) { # without 0 = header
334             $self->_clear_comment;
335             $entry_ref->{msgid}
336 15   66     679 = $po->msgid
337             && $encode_obj->decode( $po->dequote( $po->msgid ) );
338             $entry_ref->{msgid_plural}
339 15   66     187 = defined $po->msgid_plural
340             && $encode_obj->decode( $po->dequote( $po->msgid_plural ) );
341             $entry_ref->{msgstr}
342 15 50       407 = defined $po->msgstr
343 15         48 && $po->dequote( $po->msgstr );
344 15   100     54 length $entry_ref->{msgstr}
345 15         156 and next MESSAGE;
346 15         53 $entry_ref->{msgstr_n} = {};
347             my $msgstr_n = $po->msgstr_n || {};
348             my $is_all_translated = 1;
349 30   66     108 for my $index ( 0 .. ( $nplurals - 1 ) ) {
350             $entry_ref->{msgstr_n}->{$index}
351             = defined $msgstr_n->{$index}
352 30   33     176 && $po->dequote( $msgstr_n->{$index} );
353 30   66     108 my $is_translated
354             = defined $entry_ref->{msgstr_n}->{$index}
355             && length $entry_ref->{msgstr_n}->{$index};
356 15 50       33 $is_all_translated &&= $is_translated;
357 15 100       130 }
    100          
    100          
358 2 50       6 $is_all_translated
359 2         12 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         27 }
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         12 $self->_translate_gettext($entry_ref, $po);
373             }
374 11         32 else {
375             $self->_translate_simple($entry_ref, $po);
376 2 50       15 }
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   3131 }
382 2         15 }
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       2583 \A (?: Before | After )
394             (?: \Q paragraph\E | \Q line\E )?
395 6         69 \Q translation break\E \b
396             }xms or confess $_;
397 6         2662 ## use critic (ComplexRegexes)
398             };
399            
400             return $self;
401 7     7   19 }
402            
403 7 100       20 sub _encode_named {
404 7         26 my ( $self, $msgid, $num ) = @_;
405            
406 14     14   48 $num = defined $num ? $num : 1;
407 14         54 $self->_clear_num_ref;
408 14 100       36 my $encode_placeholder = sub {
409 7         26 my ( $placeholder, $is_num ) = @_;
410 7         43 local *__ANON__ = '$encode_placeholder->'; ## no critic (InterpolationOfMetachars LocalVars)
411             if ( $is_num ) {
412 7         24 $self->_num_ref->{$num} = $placeholder;
413 7         44 return $num++;
414             }
415 7         59 return $self->_encode_named_placeholder($placeholder);
416             };
417             ## no critic (EscapedMetacharacters)
418             $msgid =~ s{
419             ( \\ \{ )
420             | (
421             \{
422             [^\{\}:]+
423             ( [:] ( num )? [^\{\}]* )?
424 14 50       95 \}
425             )
426             }
427             {
428             $1
429 7         38 || $encode_placeholder->($2, $3)
430             }xmsge;
431             ## use critic (EscapedMetacharacters)
432            
433 6     6   14 return $msgid;
434             }
435 6         29
436 6 100       40 sub _decode_named {
437             my ( $self, $msgstr ) = @_;
438 6         40
439             $msgstr =~ s{ ( \d+ ) }{
440 6         14 exists $self->_num_ref->{$1} ? $self->_num_ref->{$1} : $1
441             }xmsge;
442             $msgstr = $self->_decode_named_placeholder($msgstr);
443            
444 3     3   9 return $msgstr;
445             }
446 3         33
447 3         9 sub _translate_named {
448 2         13 my ( $self, $entry_ref, $po ) = @_;
449 2         22
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   5 return;
456             }
457 2         5
458 2         4 sub _translate_named_plural {
459             my ( $self, $entry_ref, $po ) = @_;
460 2         4
  2         10  
461             my $msgid = $entry_ref->{msgid};
462 4 50 33     55 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       23 and length $entry_ref->{msgstr_n}->{$index}
467             and next MSGSTR_N;
468             my $any_msgid = $self->_encode_named(
469 4         12 $index
470 4         20 ? ( $msgid_plural, $self->_plural_ref->{$index} )
471             : $msgid,
472 4         24 );
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   31 return;
480             }
481            
482             sub _encode_gettext_inner { ## no critic (ManyArgs)
483 6   100     37 my ( $self, $quant, $number, $inner, $singular, $plural, $zero ) = @_;
484 12 100 66     66
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   19 return $encode_az->("$quant,$number,$inner");
494             }
495            
496 8         72 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       160 [)]
    50          
511             |
512             [%] ( \d+ ) # simple
513             }
514             {
515             $1
516             ? $1
517             : $2
518 8         30 ? $self->_encode_gettext_inner($2, $3, $4, $5, $6, $7)
519             : $encode_az->($8)
520             }xmsge;
521             ## use critic (ComplexRegexes)
522 8     8   24
523             return $msgid;
524 8         19 }
525 8 100       33
526 5         29 sub _decode_gettext_inner {
527             my ( $self, $inner ) = @_;
528 3 50       14
529 3         16 $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         35  
  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   11
543             return "DECODE_ERROR($inner)";
544 5         27 }
545            
546             sub _decode_gettext {
547             my ( $self, $msgstr ) = @_;
548            
549 8         25 $msgstr =~ s{
550             XX
551             ( [[:upper:]]+? )
552 5         14 XZ
553             }
554             {
555             $self->_decode_gettext_inner($1)
556 8     8   24 }xmsge;
557            
558 8         34 return $msgstr;
559 8         32 }
560 8         45
561 5         20 sub _translate_gettext {
562 5         53 my ( $self, $entry_ref, $po ) = @_;
563            
564 5         85 $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   6 $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   32 );
581            
582 11 100       244 return;
583             }
584 6 50       141
585             sub _update_comment {
586 6 100       45 my ( $self, $po ) = @_;
587 5         98
588 5         53 defined $self->comment
589             or return;
590             length $self->comment
591             or return;
592 1         7 if ( ! defined $po->comment ) {
  2         44  
593             $po->comment( $self->comment );
594             return;
595 1         22 }
596             my @lines
597 1         12 = grep {
598             $_ ne $self->comment;
599             }
600             $po->comment =~ m{ [\n]* ( [^\n]+ ) }xmsg;
601 6     6 1 114 $po->comment( join "\n", $self->comment, @lines );
602            
603 6 50       23 return;
604             }
605 6 50       17
606             sub with_paragraphs {
607             my ( $self, $msgid, $callback ) = @_;
608 6         34
609 6         14 ref $callback eq 'CODE'
610             or confess 'Code reference expected';
611             defined $msgid
612             or return $msgid;
613 12         50
614             my $has_network_line_endings = $msgid =~ s{ \r\n }{\n}xmsg;
615 13 100       57 my ( @prefix, @suffix );
616             my $msgstr
617 6         55 = join "\n\n",
  13         28  
618 13         49 map {
  13         39  
  13         37  
619 13         88 ( shift @prefix ) . $_ . ( shift @suffix );
  13         34  
  13         29  
620 13         40 }
621             map { length $_ ? $callback->($_) : $_ }
622             map { ## no critic (ComplexMappings)
623 5 100       25 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         36 $paragraph;
627             }
628             split m{ \n [^\S\n]* \n }xms, $msgid;
629             $has_network_line_endings
630 6     6 1 103 and $msgstr =~ s{ \n }{\r\n}xmsg;
631            
632 6 50       35 return $msgstr;
633             }
634 6 50       19
635             sub with_lines {
636             my ( $self, $msgid, $callback ) = @_;
637 6         26
638 6         10 ref $callback eq 'CODE'
639             or confess 'Code reference expected';
640             defined $msgid
641             or return $msgid;
642            
643 14         70 my $has_network_line_endings = $msgid =~ s{ \r\n }{\n}xmsg;
644             my ( @prefix, @suffix );
645 15 100       55
646             return
647 6 100       31 join $has_network_line_endings ? ( "\r\n" ) : ( "\n" ),
  15         28  
648 15         51 map {
  15         36  
  15         39  
649 15         79 ( shift @prefix ) . $_ . ( shift @suffix );
  15         35  
  15         33  
650 15         45 }
651 15         57 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   143 $line;
658             }
659 71 100       236 split m{ \n }xms, $msgid;
660             }
661 19         112
662             sub _bytes_max_fail_message {
663             my ( $self, $msgid ) = @_;
664 19 100       64
665 9         40 $self->bytes_max
666 9         59 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   73 "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       52
680             return $self->_bytes_max_fail_message($msgid)
681 7         18 ? $self->with_lines(
682 7 50       43 $msgid,
683             sub {
684 7         18 my $fail_message = $self->_bytes_max_fail_message($_);
685 7         14 $fail_message
686 7 50       17 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       79 $msgstr =~ s{ [\x{0}\x{4}] }{}xmsg; # because of mo file conflicts
692 29         98 length $msgstr
693 27 100       159 or die "No translation break\n";
694             return $msgstr;
695 27         90 },
696 27         73 )
697 27 100       93 : do {
698             my $msgstr = $self->translate_text($msgid);
699 26         80 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 658 or die "No translation break\n";
705             $msgstr;
706 31 0       124 };
    50          
707             }
708            
709             sub translate_any_msgid {
710 31 100       105 my ( $self, $msgid, $is_called_indirectly ) = @_;
711 23 100       65
712             $self->error
713             and $is_called_indirectly
714 30         292 ? ( die $self->error, "\n" )
715             : return q{};
716             if ( $self->before_translation_code ) {
717             $self->before_translation_code->($self, $msgid)
718 7         20 or die "Before translation break\n";
719 30 100   30   1406 }
720             my $fail_message = $self->_bytes_max_fail_message($msgid);
721             my $msgstr
722 4 100   4   836 = 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         9 catch {
728             if ( m{ \A \QNo translation break\E \b }xms ) {
729             ;
730 2         38 }
731             elsif ( m{ \A \QByte limit exceeded, \E }xms ) {
732 4         24 chomp;
733 30         227 $self->_error($_);
734 30 100       527 }
    100          
735             else {
736             $self->_error("API error: $_")
737             }
738 27         84 q{};
739 27 100       77 };
740 24 100       71 $self->error
741             and $is_called_indirectly
742             ? ( die $self->error, "\n" )
743             : return q{};
744 26         309 $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         3 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__