File Coverage

blib/lib/Mojolicious/Plugin/I18NUtils.pm
Criterion Covered Total %
statement 106 106 100.0
branch 10 16 62.5
condition 38 56 67.8
subroutine 19 19 100.0
pod 1 1 100.0
total 174 198 87.8


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::I18NUtils;
2              
3             # ABSTRACT: provide some helper functions for I18N
4 27     27   17977 use Mojo::Base 'Mojolicious::Plugin';
  27         76  
  27         258  
5 27     27   18979 use Time::Piece;
  27         147267  
  27         482  
6 27     27   14424 use CLDR::Number;
  27         2770846  
  27         956  
7 27     27   11541 use HTTP::AcceptLanguage;
  27         48984  
  27         824  
8              
9 27     27   11829 use Mojolicious::Plugin::I18NUtils::Locale;
  27         82  
  27         234  
10              
11             our $VERSION = '0.20';
12              
13             sub register {
14 27     27 1 23424 my ($self, $app, $config) = @_;
15              
16 27   50     152 $config //= {};
17 27   100     195 my $parse_format = $config->{format} // '%Y-%m-%d %H:%M:%S';
18              
19 27         67 my %objects;
20              
21             $app->helper( browser_languages => sub {
22 129     129   51677 my $c = shift;
23              
24 129         514 my $lang = HTTP::AcceptLanguage->new( $c->req->headers->accept_language );
25 129         12856 return $lang->languages;
26 27         261 });
27              
28             $app->helper( datetime_loc => sub {
29 50     50   453863 my $c = shift;
30 50         150 my ($date, $lang) = @_;
31              
32 50   66     332 $lang //= ($c->browser_languages)[0];
33              
34 50 50       713 return '' if !defined $date;
35              
36 50         226 my $output_format = $self->_date_long( $lang );
37 50         222 my $formatted_date = $self->_translate( $date, $parse_format, $output_format );
38              
39 50         305 return $formatted_date;
40 27         967 } );
41              
42             $app->helper( date_loc => sub {
43 60     60   586553 my $c = shift;
44 60         209 my ($date, $lang) = @_;
45              
46 60   66     390 $lang //= ($c->browser_languages)[0];
47              
48 60 50       856 return '' if !defined $date;
49              
50 60         306 my $output_format = $self->_date_short( $lang );
51 60         281 my $formatted_date = $self->_translate( $date, $parse_format, $output_format );
52              
53 60         366 return $formatted_date;
54 27         505 } );
55              
56             $app->helper( date_from_to => sub {
57 11     11   106894 my $c = shift;
58 11         48 my ($date, $from, $to) = @_;
59              
60 11         62 my $in_format = $self->_date_short( $from );
61 11         35 my $out_format = $self->_date_short( $to );
62              
63 11 50       58 $out_format = '%Y-%m-%d' if lc $to eq 'iso';
64              
65 11         57 my $formatted_date = $self->_translate( $date, $in_format, $out_format );
66              
67 11         71 return $formatted_date;
68 27         476 } );
69              
70             $app->helper( currency => sub {
71 30     30   283663 my ($c, $number, $locale, $currency, $opts) = @_;
72              
73 30   66     216 $locale //= ($c->browser_languages)[0];
74              
75 30   66     1194 $objects{cldr}->{$locale} ||= CLDR::Number->new( locale => $locale );
76 30   66     35906 $objects{cur}->{$locale} ||= $objects{cldr}->{$locale}->currency_formatter( currency_code => $currency );
77              
78 30         392857 my $cur_object = $objects{cur}->{$locale};
79              
80 30 50 66     181 if ( $opts && $opts->{cash} ) {
81 16         301 $cur_object->cash(1);
82             }
83              
84 30         5140 my $formatted = $cur_object->format( $number );
85 30         16066 $cur_object->cash(0);
86              
87 30         9269 return $formatted;
88 27         527 } );
89              
90             $app->helper( decimal => sub {
91 18     18   171743 my ($c, $number, $locale) = @_;
92              
93 18   66     124 $locale //= ($c->browser_languages)[0];
94              
95 18   66     694 $objects{cldr}->{$locale} ||= CLDR::Number->new( locale => $locale );
96 18   66     18007 $objects{dec}->{$locale} ||= $objects{cldr}->{$locale}->decimal_formatter;
97              
98 18         157521 my $formatted = $objects{dec}->{$locale}->format( $number );
99 18         13325 return $formatted;
100 27         491 } );
101              
102             $app->helper( range => sub {
103 27     27   265546 my ($c, $lower, $upper, $locale) = @_;
104              
105 27   66     163 $locale //= ($c->browser_languages)[0];
106              
107 27   66     1115 $objects{cldr}->{$locale} ||= CLDR::Number->new( locale => $locale );
108 27   66     29481 $objects{dec}->{$locale} ||= $objects{cldr}->{$locale}->decimal_formatter;
109              
110 27         243988 my $formatted = $objects{dec}->{$locale}->range( $lower, $upper );
111 27         28949 return $formatted;
112 27         517 } );
113              
114             $app->helper( at_least => sub {
115 54     54   509434 my ($c, $number, $locale) = @_;
116              
117 54   66     370 $locale //= ($c->browser_languages)[0];
118              
119 54   66     1304 $objects{cldr}->{$locale} ||= CLDR::Number->new( locale => $locale );
120 54   66     19690 $objects{dec}->{$locale} ||= $objects{cldr}->{$locale}->decimal_formatter;
121              
122 54         154340 my $formatted = $objects{dec}->{$locale}->at_least( $number );
123 54         37344 return $formatted;
124 27         547 } );
125              
126             $app->helper( locale_obj => sub {
127 26     26   236945 my ( $c, $locale) = @_;
128              
129 26   66     175 $locale //= ($c->browser_languages)[0];
130              
131 26         491 return Mojolicious::Plugin::I18NUtils::Locale->new( locale => $locale );
132 27         559 });
133             }
134              
135             sub _translate {
136 121     121   456 my ($self, $date, $in, $out) = @_;
137              
138 121 100       460 if ( length $date < 11 ) {
139 45         148 $date .= ' 00:00:00';
140             }
141              
142 121         301 my $out_date;
143              
144             {
145 121     11   252 local $SIG{__WARN__} = sub {};
  121         1000  
146              
147 121 100       391 eval {
148 121         804 my $date_obj = Time::Piece->strptime( $date, $in );
149 113         9762 $out_date = $date_obj->strftime( $out );
150 113         6132 1;
151             } or $out_date = '';
152             }
153              
154 121         10797 return $out_date;
155             }
156              
157             sub _date_long {
158 50     50   140 my ($self, $lang) = @_;
159              
160 50 50       146 return "%d/%m/%Y %H:%M:%S" if !$lang;
161              
162 50         149 $lang = lc $lang;
163 50         143 $lang =~ s/-/_/g;
164              
165 50         297 state $formats = {
166             ar_sa => '%d.%m.%Y %H:%M:%S',
167             bg => '%d.%m.%Y %H:%M:%S',
168             ca => '%d.%m.%Y %H:%M:%S',
169             cs => '%d/%m/%Y %H:%M:%S',
170             da => '%d.%m.%Y %H:%M:%S',
171             de => '%d.%m.%Y %H:%M:%S',
172             el => '%d.%m.%Y %H:%M:%S',
173             en_ca => '%Y-%m-%d %H:%M:%S',
174             en_gb => '%d/%m/%Y %H:%M:%S',
175             en => '%m/%d/%Y %H:%M:%S',
176             es_co => '%d/%m/%Y - %H:%M:%S',
177             es_mx => '%d/%m/%Y - %H:%M:%S',
178             es => '%d/%m/%Y - %H:%M:%S',
179             et => '%d.%m.%Y %H:%M:%S',
180             fa => '%d.%m.%Y %H:%M:%S',
181             fi => '%d.%m.%Y %H:%M:%S',
182             fr_ca => '%d.%m.%Y %H:%M:%S',
183             fr => '%d.%m.%Y %H:%M:%S',
184             he => '%d/%m/%Y %H:%M:%S',
185             hi => '%d/%m/%Y - %H:%M:%S',
186             hr => '%d.%m.%Y %H:%M:%S',
187             hu => '%Y.%m.%d %H:%M:%S',
188             it => '%d/%m/%Y %H:%M:%S',
189             ja => '%Y/%m/%d %H:%M:%S',
190             lt => '%Y-%m-%d %H:%M:%S',
191             lv => '%d.%m.%Y %H:%M:%S',
192             ms => '%d.%m.%Y %H:%M:%S',
193             nb_no => '%d/%m %Y %H:%M:%S',
194             nl => '%d-%m-%Y %H:%M:%S',
195             pl => '%Y-%m-%d %H:%M:%S',
196             pt_br => '%d/%m/%Y %H:%M:%S',
197             pt => '%Y-%m-%d %H:%M:%S',
198             ru => '%d.%m.%Y %H:%M:%S',
199             sk_sk => '%d.%m.%Y %H:%M:%S',
200             sl => '%d.%m.%Y %H:%M:%S',
201             sr_cyrl => '%d.%m.%Y %H:%M:%S',
202             sr_latn => '%d.%m.%Y %H:%M:%S',
203             sv => '%d/%m %Y %H:%M:%S',
204             sw => '%m/%d/%Y %H:%M:%S',
205             tr => '%d.%m.%Y %H:%M:%S',
206             uk => '%m/%d/%Y %H:%M:%S',
207             vi_vn => '%d.%m.%Y %H:%M:%S',
208             zh_cn => '%Y.%m.%d %H:%M:%S',
209             zh_tw => '%Y.%m.%d %H:%M:%S',
210             };
211              
212 50   50     259 return $formats->{$lang} // '%d/%m/%Y %H:%M:%S';
213             }
214              
215             sub _date_short {
216 82     82   239 my ($self, $lang) = @_;
217              
218 82 50       260 return "%d/%m/%Y" if !$lang;
219              
220 82         275 $lang = lc $lang;
221 82         252 $lang =~ s/-/_/g;
222              
223 82         744 state $formats = {
224             ar_sa => '%d.%m.%Y',
225             bg => '%d.%m.%Y',
226             ca => '%d.%m.%Y',
227             cs => '%d/%m/%Y',
228             da => '%d.%m.%Y',
229             de => '%d.%m.%Y',
230             el => '%d.%m.%Y',
231             en_ca => '%Y-%m-%d',
232             en_gb => '%d/%m/%Y',
233             en => '%m/%d/%Y',
234             es_co => '%d/%m/%Y',
235             es_mx => '%d/%m/%Y',
236             es => '%d/%m/%Y',
237             et => '%d.%m.%Y',
238             fa => '%d.%m.%Y',
239             fi => '%d.%m.%Y',
240             fr_ca => '%d.%m.%Y',
241             fr => '%d.%m.%Y',
242             he => '%d/%m/%Y',
243             hi => '%d/%m/%Y',
244             hr => '%d.%m.%Y',
245             hu => '%Y.%m.%d',
246             it => '%d/%m/%Y',
247             ja => '%Y/%m/%d',
248             lt => '%Y-%m-%d',
249             lv => '%d.%m.%Y',
250             ms => '%d.%m.%Y',
251             nb_no => '%d.%m.%Y',
252             nl => '%d-%m-%Y',
253             pl => '%Y-%m-%d',
254             pt_br => '%d/%m/%Y',
255             pt => '%Y-%m-%d',
256             ru => '%d.%m.%Y',
257             sk_sk => '%d.%m.%Y',
258             sl => '%d.%m.%Y',
259             sr_cyrl => '%d.%m.%Y',
260             sr_latn => '%d.%m.%Y',
261             sv => '%Y.%m.%d',
262             sw => '%m/%d/%Y',
263             tr => '%d.%m.%Y',
264             uk => '%m/%d/%Y',
265             vi_vn => '%d.%m.%Y',
266             zh_cn => '%Y.%m.%d',
267             zh_tw => '%Y.%m.%d',
268             };
269              
270 82   100     457 return $formats->{$lang} // '%d/%m/%Y';
271             }
272              
273             1;
274              
275             __END__