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   234 use strict;
  34         76  
  34         973  
4 34     34   172 use warnings;
  34         69  
  34         940  
5 34     34   198 use Carp qw(confess);
  34         86  
  34         1754  
6 34     34   15249 use Class::Load qw(load_class);
  34         672541  
  34         2077  
7 34     34   15880 use Locale::TextDomain::OO::Singleton::Lexicon;
  34         126  
  34         1291  
8 34     34   16346 use Locale::TextDomain::OO::Util::JoinSplitLexiconKeys;
  34         1553587  
  34         1641  
9 34     34   301 use Moo;
  34         92  
  34         498  
10 34     34   14041 use MooX::StrictConstructor;
  34         120  
  34         288  
11 34     34   33132 use MooX::Types::MooseLike::Base qw(Str);
  34         84  
  34         2063  
12 34     34   229 use namespace::autoclean;
  34         89  
  34         158  
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 141 my ( $class, @args ) = @_;
23            
24 36 50       276 my %arg_of = @args == 1 ? %{ $args[0] } : @args;
  0         0  
25 36         142 my $plugins = delete $arg_of{plugins};
26 36 100       153 if ( $plugins ) {
27 33 50       213 ref $plugins eq 'ARRAY'
28             or confess 'Attribute plugins expected as ArrayRef';
29            
30 33         98 my $current_plugins = join ', ', sort @{$plugins};
  33         159  
31 33 100       131 if ( defined $loaded_plugins ) {
32 2 100 66     24 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         79 for my $plugin ( @{$plugins} ) {
  31         97  
40 34 50       5360 my $package = ( 0 == index $plugin, q{+} )
41             ? $plugin
42             : "Locale::TextDomain::OO::Plugin::$plugin";
43 34         213 with $package;
44             }
45 31         39027 $loaded_plugins = $current_plugins;
46             }
47             }
48 35 100       233 if ( ! defined $loaded_plugins ) {
49 2         6 $loaded_plugins = q{};
50             }
51            
52 35         342 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   24 my ($self, $count_ref, $plural_code, $lexicon, $lexicon_key) = @_;
93            
94             my $nplurals = $lexicon->{ q{} }->{multiplural_nplurals}
95 9 50       25 or confess qq{X-Multiplural-Nplurals not found in lexicon "$lexicon_key"};
96 9 50       18 my @counts = @{$count_ref}
  9         29  
97             or confess 'Count array is empty';
98 9         16 my $index = 0;
99 9         25 while (@counts) {
100 18         93 $index *= $nplurals;
101 18         31 my $count = shift @counts;
102 18         445 $index += $plural_code->($count);
103             }
104            
105 9         105 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 5473 my ($self, $msgctxt, $msgid, $msgid_plural, $count, $is_n, $plural_callback) = @_;
132            
133 162         776 my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
134             my $lexicon_key = $key_util->join_lexicon_key({(
135             map {
136 162         790 $_ => $self->$_;
  648         14735  
137             }
138             qw( language category domain project )
139             )});
140 162         5239 my $lexicon = Locale::TextDomain::OO::Singleton::Lexicon->instance->data;
141             $lexicon = exists $lexicon->{$lexicon_key}
142 162 100       2230 ? $lexicon->{$lexicon_key}
143             : ();
144 162         295 my $ext_lexicon = do {
145 162         475 my $lexicon_class = $lexicon->{ q{} }->{lexicon_class};
146 162 50       441 $lexicon_class ? load_class($lexicon_class)->instance : ();
147             };
148            
149 162         832 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   65 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         6557 };
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     688 ),
    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       1214 if ( $plural_callback ) {
    100          
179             $plural_callback->(
180             $lexicon->{ q{} }->{plural_code}
181 4   33     16 || 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       208 or confess qq{Plural-Forms not found in lexicon "$lexicon_key"};
187 55 100       1172 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         398 my $msgstr_plural = $msg_ref->{msgstr_plural}->[$multiplural_index];
192 55 100 66     299 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       14 my $text = $lexicon
197             ? qq{Using lexicon "$lexicon_key".}
198             : qq{Lexicon "$lexicon_key" not found.};
199 4 0 33     84 $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         448 return $msgstr_plural;
218             }
219             my $msgstr = exists $msg_ref->{msgstr}
220             ? $msg_ref->{msgstr}
221 107 100       565 : ();
222 107 100 66     686 if ( ! defined $msgstr || ! length $msgstr ) { # fallback
223 17         40 $msgstr = $msgid;
224 17 50       82 my $text = $lexicon
225             ? qq{Using lexicon "$lexicon_key".}
226             : qq{Lexicon "$lexicon_key" not found.};
227 17 50 66     407 $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         10163 return $msgstr;
246             }
247            
248             sub run_filter {
249 3     3 1 80 my ( $self, $translation_ref ) = @_;
250            
251 3 100       49 $self->filter
252             or return $self;
253 2         44 $self->filter->($self, $translation_ref);
254            
255 2         39 return $self;
256             }
257            
258             __PACKAGE__->meta->make_immutable;
259            
260             1;
261            
262             __END__