File Coverage

blib/lib/Data/Localize.pm
Criterion Covered Total %
statement 103 121 85.1
branch 19 30 63.3
condition 7 14 50.0
subroutine 23 28 82.1
pod 15 16 93.7
total 167 209 79.9


line stmt bran cond sub pod time code
1             package Data::Localize;
2 6     6   91071 use Moo;
  6         57808  
  6         30  
3 6     6   9453 use Module::Load ();
  6         5716  
  6         101  
4 6     6   33 use Scalar::Util ();
  6         11  
  6         67  
5 6     6   3203 use I18N::LangTags ();
  6         27984  
  6         184  
6 6     6   2699 use I18N::LangTags::Detect ();
  6         10034  
  6         113  
7 6     6   104 use 5.008;
  6         16  
8              
9             our $VERSION = '0.00028';
10             our $AUTHORITY = 'cpan:DMAKI';
11              
12             BEGIN {
13 6 50   6   35 if (! defined &DEBUG) {
14 6         25 require constant;
15 6         517 constant->import(DEBUG => !!$ENV{DATA_LOCALIZE_DEBUG});
16             }
17             }
18              
19             BEGIN {
20 6     6   8993 if (DEBUG) {
21             require Data::Localize::Log;
22             Data::Localize::Log->import;
23             }
24             }
25              
26             has auto => (
27             is => 'rw',
28             default => sub { 1 },
29             );
30              
31             has auto_localizer => (
32             is => 'rw',
33             lazy => 1,
34             builder => "_build_auto_localizer",
35             isa => sub { $_[0]->isa('Data::Localize::Auto') },
36             );
37              
38             has _languages => (
39             is => 'rw',
40             lazy => 1,
41             builder => "_build__languages",
42             init_arg => 'languages',
43             );
44              
45             has _fallback_languages => (
46             is => 'rw',
47             lazy => 1,
48             builder => "_build__fallback_languages",
49             init_arg => 'fallback_languages',
50             );
51              
52             has _localizers => (
53             is => 'rw',
54             coerce => sub {
55             if (ref $_[0] ne 'ARRAY') {
56             Carp::croak("localizer list must be a list of Localizer objects");
57             }
58              
59             # XXX Want to deprecate this auto-instantiation
60             foreach my $args (@{$_[0]}) {
61             if (Scalar::Util::blessed($args)) {
62             next;
63             }
64              
65             my $klass = delete $args->{class};
66             if (! $klass) {
67             Carp::croak("No class provided for localizer list");
68             }
69             if ($klass !~ s/^\+//) {
70             $klass = "Data::Localize::$klass";
71             }
72             Module::Load::load($klass);
73             $args = $klass->new(%$args);
74             }
75             $_[0];
76             },
77             default => sub { +[] },
78             init_arg => 'localizers',
79             );
80              
81             has localizer_map => (
82             is => 'ro',
83             default => sub { +{} },
84             );
85              
86             sub BUILD {
87 7     7 0 39 my $self = shift;
88              
89 7 50       26 if ($self->count_localizers > 0) {
90 0         0 foreach my $loc (@{ $self->_localizers }) {
  0         0  
91 0         0 $loc->register($self);
92             }
93             }
94 7         71 return $self;
95             }
96              
97             sub _build__fallback_languages {
98 2     2   26 return [ 'en' ];
99             }
100              
101             sub _build__languages {
102 3     3   22 my $self = shift;
103 3         10 $self->detect_languages();
104             }
105              
106             sub _build_auto_localizer {
107 2     2   20 my $self = shift;
108 2         3787 require Data::Localize::Auto;
109 2         13 Data::Localize::Auto->new();
110             }
111              
112             sub set_languages {
113 3     3 1 950 my $self = shift;
114 3 50       65 $self->_languages([ @_ > 0 ? @_ : $self->detect_languages ]);
115             };
116              
117              
118             sub add_fallback_languages {
119 0     0 1 0 my $self = shift;
120 0         0 push @{$self->_fallback_languages}, @_;
  0         0  
121             }
122              
123             sub fallback_languages {
124 3     3 1 615 my $self = shift;
125 3         4 return @{$self->_fallback_languages};
  3         56  
126             }
127              
128             sub languages {
129 27     27 1 42 my $self = shift;
130 27         36 return @{$self->_languages};
  27         471  
131             }
132              
133             sub localizers {
134 3     3 1 1689 my $self = shift;
135 3         62 return $self->_localizers;
136             }
137              
138             sub count_localizers {
139 8     8 1 18 my $self = shift;
140 8         11 return scalar @{$self->_localizers};
  8         116  
141             }
142              
143             sub grep_localizers {
144 0     0 1 0 my ($self, $cb) = @_;
145 0         0 grep { $cb->($_) } @{$self->_localizers};
  0         0  
  0         0  
146             }
147              
148             sub get_localizer_from_lang {
149 44     44 1 73 my ($self, $key) = @_;
150 44         161 return $self->localizer_map->{$key};
151             }
152              
153             sub set_localizer_map {
154 14     14 1 25 my ($self, $key, $value) = @_;
155 14         33 return $self->localizer_map->{$key} = $value;
156             }
157              
158             sub detect_languages {
159 3     3 1 5 my $self = shift;
160 3   33     12 my @lang = I18N::LangTags::implicate_supers(
161             I18N::LangTags::Detect::detect() ||
162             $self->fallback_languages,
163             );
164 3         248 if (DEBUG) {
165             local $Log::Minimal::AUTODUMP = 1;
166             debugf("detect_languages: auto-detected %s", \@lang);;
167             }
168 3 50       16 return wantarray ? @lang : \@lang;
169             }
170              
171             sub detect_languages_from_header {
172 0     0 1 0 my $self = shift;
173             my @lang = I18N::LangTags::implicate_supers(
174 0   0     0 I18N::LangTags::Detect->http_accept_langs( $_[0] || $ENV{HTTP_ACCEPT_LANGUAGE}),
175             $self->fallback_languages,
176             );
177 0         0 if (DEBUG) {
178             local $Log::Minimal::AUTODUMP = 1;
179             debugf("detect_languages_from_header detected %s", \@lang);
180             }
181 0 0       0 return wantarray ? @lang : \@lang;
182             }
183              
184             sub localize {
185 24     24 1 1241 my ($self, $key, @args) = @_;
186              
187 24         33 if (DEBUG) {
188             debugf("localize - Looking up key '%s'", $key);
189             }
190 24         57 my @languages = $self->languages ;
191 24         136 if (DEBUG) {
192             local $Log::Minimal::AUTODUMP = 1;
193             debugf("localize - Loaded languages %s", \@languages);
194             }
195 24         38 foreach my $lang (@languages) {
196 25         27 if (DEBUG) {
197             debugf("localize - Attempting language '%s'", $lang);
198             }
199 25   100     64 my $localizers = $self->get_localizer_from_lang($lang) || [];
200 25         39 if (DEBUG) {
201             debugf("localize - Loaded %d localizers for lang %s",
202             scalar @$localizers,
203             $lang
204             );
205             }
206 25         54 foreach my $localizer (@$localizers) {
207 22         27 if (DEBUG) {
208             local $Log::Minimal::AUTODUMP = 1;
209             debugf("localize - Trying with %s", $localizer);
210             }
211 22         82 my $out = $localizer->localize_for(
212             lang => $lang,
213             id => $key,
214             args => \@args
215             );
216              
217 22 100       53 if ($out) {
218 19         23 if (DEBUG) {
219             debugf("localize - Got localization: '%s'", $out);
220             }
221 19         89 return $out;
222             }
223             }
224             }
225              
226 5         9 if (DEBUG) {
227             debugf("localize - nothing found in registered languages");
228             }
229              
230             # if we got here, we missed on all languages.
231             # one last shot. try the '*' slot
232 5 100       8 foreach my $localizer (@{$self->get_localizer_from_lang('*') || []}) {
  5         20  
233 3         8 foreach my $lang ($self->languages) {
234 4         20 if (DEBUG) {
235             debugf("localize - trying %s for '*' with localizer %s",
236             $lang,
237             $localizer
238             );
239             }
240 4         13 my $out = $localizer->localize_for(
241             lang => $lang,
242             id => $key,
243             args => \@args
244             );
245 4 100       12 if ($out) {
246 1         2 if (DEBUG) {
247             debugf("localize - found for %s, adding to map", $lang);
248             }
249              
250             # oh, found one? set it in the localizer map so we don't have
251             # to look it up again
252 1         3 $self->add_localizer_map($lang, $localizer);
253 1         3 return $out;
254             }
255             }
256             }
257              
258             # if you got here, and you /still/ can't find a proper localization,
259             # then we fallback to 'auto' feature
260 4 100       21 if ($self->auto) {
261 3         4 if (DEBUG) {
262             debugf("localize - trying auto-lexicon for '%s'", $key);
263             }
264 3         53 return $self->auto_localizer->localize_for(id => $key, args => \@args);
265             }
266              
267 1         5 return ();
268             }
269              
270             sub add_localizer {
271 6     6 1 32 my $self = shift;
272              
273 6         12 my $localizer;
274 6 100       29 if (@_ == 1) {
275 2         4 $localizer = $_[0];
276             } else {
277 4         23 my %args = @_;
278              
279 4         9 my $klass = delete $args{class};
280 4 50       18 if ($klass !~ s/^\+//) {
281 4         12 $klass = "Data::Localize::$klass";
282             }
283 4         19 Module::Load::load($klass);
284 4         147 if (Data::Localize::DEBUG) {
285             local $Log::Minimal::AUTODUMP = 1;
286             debugf("Creating localizer '%s' (%s)", $klass, \%args);
287             }
288 4         53 $localizer = $klass->new(%args);
289             }
290              
291 6 100 66     225 if (! $localizer || ! Scalar::Util::blessed($localizer) || ! $localizer->isa( 'Data::Localize::Localizer' ) ) {
      66        
292 1 50       153 Carp::confess("Bad localizer: '" . ( defined $localizer ? $localizer : '(null)' ) . "'");
293             }
294              
295 5         11 if (DEBUG()) {
296             debugf("add_localizer: %s", $localizer);
297             }
298 5         130 $localizer->register($self);
299 5         13 push @{ $self->_localizers }, $localizer;
  5         90  
300             }
301              
302             sub find_localizers {
303 0     0 1 0 my ($self, %args) = @_;
304              
305 0 0       0 if (my $isa = $args{isa}) {
306 0     0   0 return $self->grep_localizers(sub { $_[0]->isa($isa) });
  0         0  
307             }
308             }
309              
310             sub add_localizer_map {
311 14     14 1 28 my ($self, $lang, $localizer) = @_;
312              
313 14         14 if (DEBUG) {
314             debugf("add_localizer_map %s -> %s", $lang, $localizer);
315             }
316 14         31 my $list = $self->get_localizer_from_lang($lang);
317 14 50       30 if (! $list) {
318 14         21 $list = [];
319 14         31 $self->set_localizer_map($lang, $list);
320             }
321 14         84 unshift @$list, $localizer;
322             }
323              
324             1;
325              
326             __END__