File Coverage

blib/lib/Template/Plugin/Gettext.pm
Criterion Covered Total %
statement 225 240 93.7
branch 41 84 48.8
condition 16 51 31.3
subroutine 48 51 94.1
pod 15 16 93.7
total 345 442 78.0


line stmt bran cond sub pod time code
1             #! /bin/false
2              
3             # Copyright (C) 2016-2018 Guido Flohr ,
4             # all rights reserved.
5              
6             # This program is free software; you can redistribute it and/or modify it
7             # under the terms of the GNU Library General Public License as published
8             # by the Free Software Foundation; either version 2, or (at your option)
9             # any later version.
10              
11             # This program is distributed in the hope that it will be useful,
12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14             # Library General Public License for more details.
15              
16             # You should have received a copy of the GNU Library General Public
17             # License along with this program; if not, write to the Free Software
18             # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19             # USA.
20              
21             # ABSTRACT: Gettext Support For the Template Toolkit Version 2
22              
23             package Template::Plugin::Gettext;
24             $Template::Plugin::Gettext::VERSION = '1.0';
25 5     5   281134 use strict;
  5         14  
  5         209  
26              
27 5     5   2868 use Locale::TextDomain 1.30 qw(com.cantanea.Template-Plugin-Gettext);
  5         93919  
  5         40  
28 5     5   145537 use Locale::Messages;
  5         16  
  5         194  
29 5     5   2998 use Locale::Util qw(web_set_locale);
  5         21227  
  5         330  
30 5     5   40 use Encode;
  5         16  
  5         405  
31              
32 5     5   40 use Cwd qw(abs_path);
  5         14  
  5         209  
33              
34 5     5   35 use base qw(Template::Plugin);
  5         26  
  5         2774  
35              
36             my %bound_dirs;
37             my %textdomains;
38              
39             our @DEFAULT_DIRS;
40             our @LOCALE_DIRS;
41              
42             sub __find_domain($);
43             sub __expand($%);
44             sub __fixup;
45              
46             BEGIN {
47 5     5   4269 foreach my $dir (qw('/usr/share/locale /usr/local/share/locale')) {
48 10 50       18139 if (-d $dir) {
49 0         0 push @DEFAULT_DIRS, $dir;
50 0         0 last;
51             }
52             }
53             }
54              
55             sub new {
56 57     57 1 190713 my ($class, $ctx, $textdomain, $language, $charset, @search_dirs) = @_;
57              
58 57         142 my $self = bless {}, $class;
59              
60 57 50 33     201 $textdomain = 'textdomain' unless defined $textdomain && length $textdomain;
61 57 50 33     198 $charset = 'utf-8' unless defined $charset && length $charset;
62              
63 57         229 my $template = $ctx->stash->get('component')->name;
64 57 50 33     1570 if ('input text' eq $template || 'input file handle' eq $template) {
65 57         145 my $maybe_template = $ctx->stash->get('gettext_filename');
66 57 50 33     1088 $template = $maybe_template
67             if defined $maybe_template && length $maybe_template;
68             }
69 57         143 $textdomains{$textdomain}->{$template} = 1;
70              
71 57 100       176 unless (exists $bound_dirs{$textdomain}) {
72 56 50       142 unless (@search_dirs) {
73 56         569 @search_dirs = map $_ . '/LocaleData', @INC;
74 56         126 push @search_dirs, @DEFAULT_DIRS;
75             }
76 56         106 unshift @search_dirs, @LOCALE_DIRS;
77 56         201 $bound_dirs{$textdomain} = [@search_dirs];
78             }
79              
80 57         150 $self->{__textdomain} = $textdomain;
81 57 50       127 $self->{__locale} = web_set_locale $language, $charset if defined $language;
82              
83             $ctx->define_filter(gettext => sub {
84 3     3   217 my ($context) = @_;
85              
86             return sub {
87 3         85 return __gettext($textdomain, shift);
88 3         15 };
89 57         360 }, 1);
90             $ctx->define_filter(ngettext => sub {
91 4     4   189 my ($context, @args) = @_;
92 4 50       17 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
93              
94 4         11 push @args, %$pairs;
95             return sub {
96 4         83 return __ngettext($textdomain, shift, @args);
97 4         21 };
98 57         1616 }, 1);
99             $ctx->define_filter(pgettext => sub {
100 2     2   97 my ($context, @args) = @_;
101 2 50       9 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
102              
103 2         6 push @args, %$pairs;
104             return sub {
105 2         43 return __pgettext($textdomain, shift, @args);
106 2         12 };
107 57         1293 }, 1);
108             $ctx->define_filter(gettextp => sub {
109 2     2   98 my ($context, @args) = @_;
110 2 50       11 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
111              
112 2         16 push @args, %$pairs;
113             return sub {
114 2         45 return __gettextp($textdomain, shift, @args);
115 2         10 };
116 57         1290 }, 1);
117             $ctx->define_filter(npgettext => sub {
118 4     4   195 my ($context, @args) = @_;
119 4 50       13 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
120              
121 4         13 push @args, %$pairs;
122             return sub {
123 4         81 return __npgettext($textdomain, shift, @args);
124 4         20 };
125 57         1220 }, 1);
126             $ctx->define_filter(ngettextp => sub {
127 4     4   191 my ($context, @args) = @_;
128 4 50       13 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
129              
130 4         13 push @args, %$pairs;
131             return sub {
132 4         88 return __ngettextp($textdomain, shift, @args);
133 4         21 };
134 57         1217 }, 1);
135             $ctx->define_filter(xgettext => sub {
136 3     3   169 my ($context, @args) = @_;
137 3 50       15 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
138              
139 3         13 push @args, %$pairs;
140             return sub {
141 3         72 return __xgettext($textdomain, shift, @args);
142 3         30 };
143 57         1196 }, 1);
144             $ctx->define_filter(nxgettext => sub {
145 4     4   191 my ($context, @args) = @_;
146 4 50       16 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
147              
148 4         15 push @args, %$pairs;
149             return sub {
150 4         88 return __nxgettext($textdomain, shift, @args);
151 4         21 };
152 57         1179 }, 1);
153             $ctx->define_filter(pxgettext => sub {
154 2     2   97 my ($context, @args) = @_;
155 2 50       11 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
156              
157 2         8 push @args, %$pairs;
158             return sub {
159 2         46 return __pxgettext($textdomain, shift, @args);
160 2         12 };
161 57         1181 }, 1);
162             $ctx->define_filter(xgettextp => sub {
163 2     2   105 my ($context, @args) = @_;
164 2 50       40 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
165              
166 2         9 push @args, %$pairs;
167             return sub {
168 2         50 return __xgettextp($textdomain, shift, @args);
169 2         13 };
170 57         1192 }, 1);
171             $ctx->define_filter(npxgettext => sub {
172 4     4   192 my ($context, @args) = @_;
173 4 50       14 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
174              
175 4         15 push @args, %$pairs;
176             return sub {
177 4         84 return __npxgettext($textdomain, shift, @args);
178 4         23 };
179 57         1213 }, 1);
180             $ctx->define_filter(nxgettextp => sub {
181 4     4   195 my ($context, @args) = @_;
182 4 50       15 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
183              
184 4         13 push @args, %$pairs;
185             return sub {
186 4         89 return __nxgettextp($textdomain, shift, @args);
187 4         20 };
188 57         1179 }, 1);
189              
190 57         1159 return $self;
191             }
192              
193             sub __fixup {
194 56     56   2812 my $trans = $_[-1];
195              
196 56         196 Encode::_utf8_on($trans);
197              
198 56         888 return $trans;
199             }
200              
201             sub __gettext {
202 4     4   9 my ($textdomain, $msgid) = @_;
203              
204 4         324 local %ENV = %ENV;
205 4         27 delete $ENV{LANGUAGE};
206              
207             __find_domain $textdomain
208 4 50 33     37 if defined $textdomain && exists $bound_dirs{$textdomain};
209              
210 4         14 return __fixup $msgid, Locale::Messages::dgettext($textdomain => $msgid);
211             }
212              
213             sub gettext {
214 1     1 1 39 my ($self, $msgid) = @_;
215              
216 1         4 return __gettext $self->{__textdomain}, $msgid;
217             }
218              
219             sub __ngettext {
220 6     6   15 my ($textdomain, $msgid, $msgid_plural, $count) = @_;
221              
222 6         288 local %ENV = %ENV;
223 6         36 delete $ENV{LANGUAGE};
224              
225             __find_domain $textdomain
226 6 50 33     48 if defined $textdomain && exists $bound_dirs{$textdomain};
227              
228 6         28 return __fixup $msgid, $msgid_plural, $count,
229             Locale::Messages::dngettext($textdomain => $msgid,
230             $msgid_plural, $count);
231             }
232              
233             sub ngettext {
234 2     2 1 52 my ($self, $msgid, $msgid_plural, $count) = @_;
235              
236 2         9 return __ngettext $self->{__textdomain}, $msgid, $msgid_plural, $count;
237             }
238              
239             sub __pgettext {
240 3     3   7 my ($textdomain, $context, $msgid) = @_;
241              
242 3         141 local %ENV = %ENV;
243 3         19 delete $ENV{LANGUAGE};
244              
245             __find_domain $textdomain
246 3 50 33     31 if defined $textdomain && exists $bound_dirs{$textdomain};
247              
248 3         16 return __fixup $msgid,
249             Locale::Messages::dpgettext($textdomain => $context, $msgid);
250             }
251              
252             sub pgettext {
253 1     1 1 26 my ($self, $context, $msgid) = @_;
254              
255 1         4 return __pgettext $self->{__textdomain}, $context, $msgid;
256             }
257              
258             sub __gettextp {
259 3     3   9 my ($textdomain, $msgid, $context) = @_;
260              
261 3         146 local %ENV = %ENV;
262 3         20 delete $ENV{LANGUAGE};
263              
264             __find_domain $textdomain
265 3 50 33     30 if defined $textdomain && exists $bound_dirs{$textdomain};
266              
267 3         13 return __fixup $msgid,
268             Locale::Messages::dpgettext($textdomain => $context, $msgid);
269             }
270              
271             sub gettextp {
272 1     1 1 26 my ($self, $msgid, $context) = @_;
273              
274 1         4 return __gettextp $self->{__textdomain}, $msgid, $context;
275             }
276              
277             sub __npgettext {
278 6     6   17 my ($textdomain, $context, $msgid, $msgid_plural, $count) = @_;
279              
280 6         282 local %ENV = %ENV;
281 6         37 delete $ENV{LANGUAGE};
282              
283             __find_domain $textdomain
284 6 50 33     55 if defined $textdomain && exists $bound_dirs{$textdomain};
285              
286 6         42 return __fixup $msgid, $msgid_plural, $count,
287             Locale::Messages::dnpgettext($textdomain, $context, $msgid,
288             $msgid_plural, $count);
289             }
290              
291             sub npgettext {
292 2     2 1 62 my ($self, $context, $msgid, $msgid_plural, $count) = @_;
293              
294 2         5 return __npgettext $self->{__textdomain}, $context, $msgid, $msgid_plural,
295             $count;
296             }
297              
298             sub __ngettextp {
299 6     6   18 my ($textdomain, $msgid, $msgid_plural, $count, $context) = @_;
300              
301 6         328 local %ENV = %ENV;
302 6         38 delete $ENV{LANGUAGE};
303              
304             __find_domain $textdomain
305 6 50 33     50 if defined $textdomain && exists $bound_dirs{$textdomain};
306              
307 6         37 return __fixup $msgid, $msgid_plural, $count,
308             Locale::Messages::dnpgettext($textdomain => $context, $msgid,
309             $msgid_plural, $count);
310             }
311              
312             sub ngettextp {
313 2     2 0 52 my ($self, $msgid, $msgid_plural, $count, $context) = @_;
314              
315 2         40 return __ngettextp $self->{__textdomain}, $msgid, $msgid_plural, $count,
316             $context;
317             }
318              
319             sub __xgettext {
320 4     4   32 my ($textdomain, $msgid, %vars) = @_;
321              
322 4         213 local %ENV = %ENV;
323 4         47 delete $ENV{LANGUAGE};
324              
325             __find_domain $textdomain
326 4 50 33     41 if defined $textdomain && exists $bound_dirs{$textdomain};
327              
328 4         23 return __expand((__fixup $msgid,
329             Locale::Messages::dgettext($textdomain => $msgid)), %vars);
330             }
331              
332             sub xgettext {
333 1     1 1 38 my ($self, $msgid, @args) = @_;
334            
335 1 50       5 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
336 1         4 push @args, %$pairs;
337              
338 1         3 return __xgettext $self->{__textdomain}, $msgid, @args;
339             }
340              
341             sub __nxgettext {
342 6     6   23 my ($textdomain, $msgid, $msgid_plural, $count, %vars) = @_;
343              
344 6         278 local %ENV = %ENV;
345 6         37 delete $ENV{LANGUAGE};
346              
347             __find_domain $textdomain
348 6 50 33     48 if defined $textdomain && exists $bound_dirs{$textdomain};
349              
350 6         32 return __expand((__fixup $msgid, $msgid_plural, $count,
351             Locale::Messages::dngettext($textdomain => $msgid,
352             $msgid_plural,
353             $count)),
354             %vars);
355             }
356              
357             sub nxgettext {
358 2     2 1 61 my ($self, $msgid, $msgid_plural, $count, @args) = @_;
359              
360 2 50       8 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
361 2         8 push @args, %$pairs;
362              
363 2         5 return __nxgettext $self->{__textdomain}, $msgid, $msgid_plural, $count,
364             @args;
365             }
366              
367             sub __pxgettext {
368 3     3   51 my ($textdomain, $context, $msgid, %vars) = @_;
369              
370 3         140 local %ENV = %ENV;
371 3         18 delete $ENV{LANGUAGE};
372              
373             __find_domain $textdomain
374 3 50 33     28 if defined $textdomain && exists $bound_dirs{$textdomain};
375              
376 3         18 return __expand((__fixup $msgid,
377             Locale::Messages::dpgettext($textdomain => $context,
378             $msgid)),
379             %vars);
380             }
381              
382             sub pxgettext {
383 1     1 1 32 my ($self, $context, @args) = @_;
384            
385 1 50       6 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
386 1         3 push @args, %$pairs;
387              
388 1         4 return __pxgettext $self->{__textdomain}, $context, @args;
389             }
390              
391             sub __xgettextp {
392 3     3   15 my ($textdomain, $msgid, $context, %vars) = @_;
393              
394 3         154 local %ENV = %ENV;
395 3         31 delete $ENV{LANGUAGE};
396              
397             __find_domain $textdomain
398 3 50 33     34 if defined $textdomain && exists $bound_dirs{$textdomain};
399              
400 3         13 return __expand((__fixup $msgid,
401             Locale::Messages::dpgettext($textdomain => $context,
402             $msgid)),
403             %vars);
404             }
405              
406             sub xgettextp {
407 1     1 1 28 my ($self, $msgid, @args) = @_;
408            
409 1 50       5 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
410 1         4 push @args, %$pairs;
411              
412 1         4 return __xgettextp $self->{__textdomain}, $msgid, @args;
413             }
414              
415             sub __npxgettext {
416 6     6   25 my ($textdomain, $context, $msgid, $msgid_plural, $count, %vars) = @_;
417              
418 6         293 local %ENV = %ENV;
419 6         37 delete $ENV{LANGUAGE};
420              
421             __find_domain $textdomain
422 6 50 33     47 if defined $textdomain && exists $bound_dirs{$textdomain};
423              
424 6         26 return __expand((__fixup $msgid, $msgid_plural, $count,
425             Locale::Messages::dnpgettext($textdomain => $context,
426             $msgid, $msgid_plural,
427             $count)),
428             %vars);
429             }
430              
431             sub npxgettext {
432 2     2 1 57 my ($self, $context, @args) = @_;
433            
434 2 50       8 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
435 2         7 push @args, %$pairs;
436              
437 2         7 return __npxgettext $self->{__textdomain}, $context, @args;
438             }
439              
440             sub __nxgettextp {
441 6     6   23 my ($textdomain, $msgid, $msgid_plural, $count, $context, %vars) = @_;
442              
443 6         274 local %ENV = %ENV;
444 6         50 delete $ENV{LANGUAGE};
445              
446             __find_domain $textdomain
447 6 50 33     53 if defined $textdomain && exists $bound_dirs{$textdomain};
448              
449 6         29 return __expand((__fixup $msgid, $msgid_plural, $count,
450             Locale::Messages::dnpgettext($textdomain => $context,
451             $msgid, $msgid_plural,
452             $count)),
453             %vars);
454             }
455              
456             sub nxgettextp {
457 2     2 1 57 my ($self, $msgid, @args) = @_;
458            
459 2 50       10 my $pairs = ref $args[-1] eq 'HASH' ? pop(@args) : {};
460 2         26 push @args, %$pairs;
461              
462 2         9 return __nxgettextp $self->{__textdomain}, $msgid, @args;
463             }
464              
465             sub debug_locale {
466 0     0 1 0 shift->{__locale};
467             }
468              
469             sub __expand($%) {
470 28     28   90 my ($str, %vars) = @_;
471              
472 28         69 my $re = join '|', map { quotemeta } keys %vars;
  28         107  
473 28         386 $str =~ s/\{($re)\}/exists $vars{$1} ?
474 19 50       145 (defined $vars{$1} ? $vars{$1} : '') : "{$1}"/ge;
    50          
475              
476 28         810 return $str;
477             }
478              
479             sub __find_domain($) {
480 56     56   122 my ($domain) = @_;
481              
482 56         142 my $try_dirs = $bound_dirs{$domain};
483              
484 56 50       177 if (defined $try_dirs) {
485 56         91 my $found_dir = '';
486              
487 56         122 TRYDIR: foreach my $dir (map {abs_path $_} grep { -d $_ } @$try_dirs) {
  0         0  
  672         5998  
488             # Is there a message catalog?
489              
490 0         0 local *DIR;
491 0 0       0 if (opendir DIR, $dir) {
492 0         0 my @files = map { "$dir/$_/LC_MESSAGES/$domain.mo" }
493 0         0 grep { ! /^\.\.?$/ } readdir DIR;
  0         0  
494 0         0 foreach my $file (@files) {
495 0 0 0     0 if (-f $file || -l $file) {
496 0         0 $found_dir = $dir;
497 0         0 last TRYDIR;
498             }
499             }
500             }
501             }
502              
503             # If $found_dir is undef, the default search directories are
504             # used.
505 56         299 Locale::Messages::bindtextdomain($domain => $found_dir);
506             }
507              
508 56         1028 delete $bound_dirs{$domain};
509              
510 56         203 return 1;
511             }
512              
513             sub textdomains {
514 0     0 1   return %textdomains;
515             }
516              
517             sub resetTextdomains {
518 0     0 1   undef %textdomains;
519             }
520              
521             1;