File Coverage

blib/lib/Locale/TextDomain/OO/Translator.pm
Criterion Covered Total %
statement 90 91 98.9
branch 44 64 68.7
condition 10 20 50.0
subroutine 15 15 100.0
pod 3 3 100.0
total 162 193 83.9


line stmt bran cond sub pod time code
1             package Locale::TextDomain::OO::Translator; ## no critic (TidyCode)
2            
3 34     34   205 use strict;
  34         70  
  34         888  
4 34     34   153 use warnings;
  34         57  
  34         801  
5 34     34   181 use Carp qw(confess);
  34         71  
  34         1572  
6 34     34   15870 use Class::Load qw(load_class);
  34         631063  
  34         1926  
7 34     34   14377 use Locale::TextDomain::OO::Singleton::Lexicon;
  34         118  
  34         1227  
8 34     34   14473 use Locale::TextDomain::OO::Util::JoinSplitLexiconKeys;
  34         1394296  
  34         1437  
9 34     34   245 use Moo;
  34         74  
  34         402  
10 34     34   11639 use MooX::StrictConstructor;
  34         68  
  34         306  
11 34     34   29148 use MooX::Types::MooseLike::Base qw(Str);
  34         68  
  34         1846  
12 34     34   188 use namespace::autoclean;
  34         58  
  34         129  
13            
14             our $VERSION = '1.035';
15            
16             with qw(
17             Locale::TextDomain::OO::Role::Logger
18             );
19            
20             my $loaded_plugins;
21             sub load_plugins {
22 36     36 1 128 my ( $class, @args ) = @_;
23            
24 36 50       229 my %arg_of = @args == 1 ? %{ $args[0] } : @args;
  0         0  
25 36         114 my $plugins = delete $arg_of{plugins};
26 36 100       141 if ( $plugins ) {
27 33 50       185 ref $plugins eq 'ARRAY'
28             or confess 'Attribute plugins expected as ArrayRef';
29            
30 33         173 my $current_plugins = join ', ', sort @{$plugins};
  33         152  
31 33 100       125 if ( defined $loaded_plugins ) {
32 2 100 66     34 length $current_plugins
33             and $loaded_plugins ne $current_plugins
34             and confess
35             "Too late to load plugins $current_plugins.",
36             " Another method new was called before with plugins $loaded_plugins";
37             }
38             else {
39 31         68 for my $plugin ( @{$plugins} ) {
  31         82  
40 34 50       4625 my $package = ( 0 == index $plugin, q{+} )
41             ? $plugin
42             : "Locale::TextDomain::OO::Plugin::$plugin";
43 34         182 with $package;
44             }
45 31         34169 $loaded_plugins = $current_plugins;
46             }
47             }
48 35 100       168 if ( ! defined $loaded_plugins ) {
49 2         4 $loaded_plugins = q{};
50             }
51            
52 35         301 return \%arg_of;
53             }
54            
55             has language => (
56             is => 'rw',
57             isa => Str,
58             default => 'i-default',
59             );
60            
61             has [ qw( category domain ) ] => (
62             is => 'rw',
63             isa => Str,
64             default => q{},
65             );
66            
67             has project => (
68             is => 'rw',
69             isa => sub {
70             my $project = shift;
71             defined $project
72             or return;
73             return Str->($project);
74             },
75             );
76            
77             has filter => (
78             is => 'rw',
79             isa => sub {
80             my $arg = shift;
81             # Undef
82             defined $arg
83             or return;
84             # CodeRef
85             ref $arg eq 'CODE'
86             and return;
87             confess "$arg is not Undef or CodeRef";
88             },
89             );
90            
91             sub _calculate_multiplural_index {
92 9     9   17 my ($self, $count_ref, $plural_code, $lexicon, $lexicon_key) = @_;
93            
94             my $nplurals = $lexicon->{ q{} }->{multiplural_nplurals}
95 9 50       20 or confess qq{X-Multiplural-Nplurals not found in lexicon "$lexicon_key"};
96 9 50       14 my @counts = @{$count_ref}
  9         25  
97             or confess 'Count array is empty';
98 9         14 my $index = 0;
99 9         19 while (@counts) {
100 18         77 $index *= $nplurals;
101 18         22 my $count = shift @counts;
102 18         343 $index += $plural_code->($count);
103             }
104            
105 9         59 return $index;
106             }
107            
108             # The reason we need that here is "gettext_to_maketext => 1" during load lexicon.
109             # That escaps all [ ] before it is changing %1 to [_1] or similar.
110             # And so all none gettext strings are also involved.
111             my $escape_maketext = sub {
112             my $string = shift;
113            
114             defined $string
115             or return $string;
116             $string =~ s{ ( [\[\]] ) }{~$1}xmsg;
117            
118             return $string;
119             };
120             my $unescape_maketext = sub {
121             my $string = shift;
122            
123             defined $string
124             or return $string;
125             $string =~ s{ [~] ( [\[\]] ) }{$1}xmsg;
126            
127             return $string;
128             };
129            
130             sub translate { ## no critic (ExcessComplexity ManyArgs)
131 162     162 1 5075 my ($self, $msgctxt, $msgid, $msgid_plural, $count, $is_n, $plural_callback) = @_;
132            
133 162         692 my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
134             my $lexicon_key = $key_util->join_lexicon_key({(
135             map {
136 162         696 $_ => $self->$_;
  648         13100  
137             }
138             qw( language category domain project )
139             )});
140 162         4564 my $lexicon = Locale::TextDomain::OO::Singleton::Lexicon->instance->data;
141             $lexicon = exists $lexicon->{$lexicon_key}
142 162 100       1998 ? $lexicon->{$lexicon_key}
143             : ();
144 162         264 my $ext_lexicon = do {
145 162         474 my $lexicon_class = $lexicon->{ q{} }->{lexicon_class};
146 162 50       397 $lexicon_class ? load_class($lexicon_class)->instance : ();
147             };
148            
149 162         734 my $msg_key = $key_util->join_message_key({
150             msgctxt => $msgctxt,
151             msgid => $msgid,
152             msgid_plural => $msgid_plural,
153             });
154             my $maketext_msg_key = sub {
155 20     20   64 return $key_util->join_message_key({
156             msgctxt => $escape_maketext->($msgctxt),
157             msgid => $escape_maketext->($msgid),
158             msgid_plural => $escape_maketext->($msgid_plural),
159             });
160 162         5791 };
161             my $msg_ref
162             = exists $lexicon->{$msg_key}
163             ? $lexicon->{$msg_key}
164             : exists $lexicon->{ $maketext_msg_key->() }
165             ? {
166             msgstr => $unescape_maketext->(
167             $lexicon->{ $maketext_msg_key->() }->{msgstr},
168 162 50 0     589 ),
    50          
    100          
169             }
170             : $ext_lexicon
171             ? $ext_lexicon->fetch_from_lexicon($lexicon_key, $msg_key)
172             || {
173             msgstr => $unescape_maketext->(
174             $ext_lexicon->fetch_from_lexicon( $lexicon_key, $maketext_msg_key->() ),
175             ),
176             }
177             : ();
178 162 100       1101 if ( $plural_callback ) {
    100          
179             $plural_callback->(
180             $lexicon->{ q{} }->{plural_code}
181 4   33     28 || confess qq{Plural-Forms not found in lexicon "$lexicon_key"},
182             );
183             }
184             elsif ( $is_n ) {
185             my $plural_code = $lexicon->{ q{} }->{plural_code}
186 55 50       158 or confess qq{Plural-Forms not found in lexicon "$lexicon_key"};
187 55 100       1141 my $multiplural_index
188             = ref $count eq 'ARRAY'
189             ? $self->_calculate_multiplural_index($count, $plural_code, $lexicon, $lexicon_key)
190             : $plural_code->($count);
191 55         349 my $msgstr_plural = $msg_ref->{msgstr_plural}->[$multiplural_index];
192 55 100 66     278 if ( ! defined $msgstr_plural || ! length $msgstr_plural ) { # fallback
193 4 100       10 $msgstr_plural = $plural_code->($count)
194             ? $msgid_plural
195             : $msgid;
196 4 50       13 my $text = $lexicon
197             ? qq{Using lexicon "$lexicon_key".}
198             : qq{Lexicon "$lexicon_key" not found.};
199 4 0 33     78 $self->language ne 'i-default'
    0          
    0          
    50          
200             and $self->logger
201             and $self->logger->(
202             (
203             sprintf
204             '%s msgstr_plural not found for msgctxt=%s, msgid=%s, msgid_plural=%s.',
205             $text,
206             ( defined $msgctxt ? qq{"$msgctxt"} : 'undef' ),
207             ( defined $msgid ? qq{"$msgid"} : 'undef' ),
208             ( defined $msgid_plural ? qq{"$msgid_plural"} : 'undef' ),
209             ),
210             {
211             object => $self,
212             type => 'warn',
213             event => 'translation,fallback',
214             },
215             );
216             }
217 55         396 return $msgstr_plural;
218             }
219             my $msgstr = exists $msg_ref->{msgstr}
220             ? $msg_ref->{msgstr}
221 107 100       530 : ();
222 107 100 66     679 if ( ! defined $msgstr || ! length $msgstr ) { # fallback
223 17         32 $msgstr = $msgid;
224 17 50       150 my $text = $lexicon
225             ? qq{Using lexicon "$lexicon_key".}
226             : qq{Lexicon "$lexicon_key" not found.};
227 17 50 66     420 $self->language ne 'i-default'
    50          
    100          
228             and $self->logger
229             and $self->logger->(
230             (
231             sprintf
232             '%s msgstr not found for msgctxt=%s, msgid=%s.',
233             $text,
234             ( defined $msgctxt ? qq{"$msgctxt"} : 'undef' ),
235             ( defined $msgid ? qq{"$msgid"} : 'undef' ),
236             ),
237             {
238             object => $self,
239             type => 'warn',
240             event => 'translation,fallback',
241             },
242             );
243             }
244            
245 107         10039 return $msgstr;
246             }
247            
248             sub run_filter {
249 3     3 1 89 my ( $self, $translation_ref ) = @_;
250            
251 3 100       53 $self->filter
252             or return $self;
253 2         43 $self->filter->($self, $translation_ref);
254            
255 2         38 return $self;
256             }
257            
258             __PACKAGE__->meta->make_immutable;
259            
260             1;
261            
262             __END__