line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DateTime::Locale; |
2
|
|
|
|
|
|
|
|
3
|
16
|
|
|
16
|
|
10103804
|
use 5.008004; |
|
16
|
|
|
|
|
155
|
|
4
|
|
|
|
|
|
|
|
5
|
16
|
|
|
16
|
|
86
|
use strict; |
|
16
|
|
|
|
|
39
|
|
|
16
|
|
|
|
|
360
|
|
6
|
16
|
|
|
16
|
|
76
|
use warnings; |
|
16
|
|
|
|
|
31
|
|
|
16
|
|
|
|
|
451
|
|
7
|
16
|
|
|
16
|
|
6207
|
use namespace::autoclean; |
|
16
|
|
|
|
|
234377
|
|
|
16
|
|
|
|
|
61
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '1.38'; |
10
|
|
|
|
|
|
|
|
11
|
16
|
|
|
16
|
|
17349
|
use DateTime::Locale::Data; |
|
16
|
|
|
|
|
526
|
|
|
16
|
|
|
|
|
1488
|
|
12
|
16
|
|
|
16
|
|
6868
|
use DateTime::Locale::FromData; |
|
16
|
|
|
|
|
63
|
|
|
16
|
|
|
|
|
568
|
|
13
|
16
|
|
|
16
|
|
118
|
use DateTime::Locale::Util qw( parse_locale_code ); |
|
16
|
|
|
|
|
35
|
|
|
16
|
|
|
|
|
781
|
|
14
|
16
|
|
|
16
|
|
94
|
use Params::ValidationCompiler 0.13 qw( validation_for ); |
|
16
|
|
|
|
|
348
|
|
|
16
|
|
|
|
|
623
|
|
15
|
16
|
|
|
16
|
|
6487
|
use Specio::Library::String; |
|
16
|
|
|
|
|
143294
|
|
|
16
|
|
|
|
|
136
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my %Class; |
18
|
|
|
|
|
|
|
my %DataForCode; |
19
|
|
|
|
|
|
|
my %NameToCode; |
20
|
|
|
|
|
|
|
my %NativeNameToCode; |
21
|
|
|
|
|
|
|
my %UserDefinedAlias; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my %LoadCache; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub register { |
26
|
8
|
|
|
8
|
0
|
9292
|
my $class = shift; |
27
|
|
|
|
|
|
|
|
28
|
8
|
|
|
|
|
54
|
%LoadCache = (); |
29
|
|
|
|
|
|
|
|
30
|
8
|
100
|
|
|
|
27
|
if ( ref $_[0] ) { |
31
|
2
|
|
|
|
|
11
|
$class->_register(%$_) foreach @_; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
else { |
34
|
6
|
|
|
|
|
19
|
$class->_register(@_); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub _register { |
39
|
9
|
|
|
9
|
|
15
|
shift; |
40
|
9
|
|
|
|
|
36
|
my %p = @_; |
41
|
|
|
|
|
|
|
|
42
|
9
|
|
|
|
|
18
|
my $id = $p{id}; |
43
|
|
|
|
|
|
|
|
44
|
9
|
100
|
|
|
|
51
|
die q{'\@' or '=' are not allowed in locale ids} |
45
|
|
|
|
|
|
|
if $id =~ /[\@=]/; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
die |
48
|
|
|
|
|
|
|
"You cannot replace an existing locale ('$id') unless you also specify the 'replace' parameter as true\n" |
49
|
7
|
50
|
33
|
|
|
39
|
if !delete $p{replace} && exists $DataForCode{$id}; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
$p{native_language} = $p{en_language} |
52
|
7
|
50
|
|
|
|
24
|
unless exists $p{native_language}; |
53
|
|
|
|
|
|
|
|
54
|
7
|
|
|
|
|
10
|
my @en_pieces; |
55
|
|
|
|
|
|
|
my @native_pieces; |
56
|
7
|
|
|
|
|
15
|
foreach my $p (qw( language script territory variant )) { |
57
|
28
|
100
|
|
|
|
75
|
push @en_pieces, $p{"en_$p"} if exists $p{"en_$p"}; |
58
|
28
|
100
|
|
|
|
65
|
push @native_pieces, $p{"native_$p"} if exists $p{"native_$p"}; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
7
|
|
|
|
|
23
|
$p{en_complete_name} = join q{ }, @en_pieces; |
62
|
7
|
|
|
|
|
18
|
$p{native_complete_name} = join q{ }, @native_pieces; |
63
|
|
|
|
|
|
|
|
64
|
7
|
|
|
|
|
28
|
$id =~ s/_/-/g; |
65
|
|
|
|
|
|
|
|
66
|
7
|
|
|
|
|
17
|
$DataForCode{$id} = \%p; |
67
|
|
|
|
|
|
|
|
68
|
7
|
|
|
|
|
18
|
$NameToCode{ $p{en_complete_name} } = $id; |
69
|
7
|
|
|
|
|
16
|
$NativeNameToCode{ $p{native_complete_name} } = $id; |
70
|
|
|
|
|
|
|
|
71
|
7
|
50
|
|
|
|
36
|
$Class{$id} = $p{class} if defined exists $p{class}; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub register_from_data { |
75
|
1
|
|
|
1
|
1
|
14
|
shift; |
76
|
|
|
|
|
|
|
|
77
|
1
|
|
|
|
|
2
|
%LoadCache = (); |
78
|
|
|
|
|
|
|
|
79
|
1
|
50
|
|
|
|
11
|
my %p = ref $_[0] ? %{ $_[0] } : @_; |
|
0
|
|
|
|
|
0
|
|
80
|
|
|
|
|
|
|
|
81
|
1
|
|
|
|
|
2
|
my $code = $p{code}; |
82
|
|
|
|
|
|
|
|
83
|
1
|
50
|
|
|
|
5
|
die q{'\@' or '=' are not allowed in locale codes} |
84
|
|
|
|
|
|
|
if $code =~ /[\@=]/; |
85
|
|
|
|
|
|
|
|
86
|
1
|
|
|
|
|
2
|
$code =~ s/_/-/g; |
87
|
|
|
|
|
|
|
|
88
|
1
|
|
|
|
|
5
|
DateTime::Locale::Data::add_locale( $code, \%p ); |
89
|
1
|
|
|
|
|
5
|
return $LoadCache{$code} = DateTime::Locale::FromData->new( \%p ); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub add_aliases { |
93
|
5
|
|
|
5
|
0
|
4947
|
shift; |
94
|
|
|
|
|
|
|
|
95
|
5
|
|
|
|
|
8
|
%LoadCache = (); |
96
|
|
|
|
|
|
|
|
97
|
5
|
50
|
|
|
|
17
|
my $aliases = ref $_[0] ? $_[0] : {@_}; |
98
|
|
|
|
|
|
|
|
99
|
5
|
|
|
|
|
7
|
for my $alias ( keys %{$aliases} ) { |
|
5
|
|
|
|
|
12
|
|
100
|
5
|
|
|
|
|
7
|
my $code = $aliases->{$alias}; |
101
|
|
|
|
|
|
|
|
102
|
5
|
100
|
|
|
|
17
|
die q{Can't alias an id to itself} |
103
|
|
|
|
|
|
|
if $alias eq $code; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# check for overwrite? |
106
|
|
|
|
|
|
|
|
107
|
4
|
|
|
|
|
9
|
my %seen = ( $alias => 1, $code => 1 ); |
108
|
4
|
|
|
|
|
4
|
my $copy = $code; |
109
|
4
|
|
|
|
|
10
|
while ( $copy = $UserDefinedAlias{$copy} ) { |
110
|
|
|
|
|
|
|
die |
111
|
|
|
|
|
|
|
"Creating an alias from $alias to $code would create a loop.\n" |
112
|
4
|
100
|
|
|
|
13
|
if $seen{$copy}; |
113
|
|
|
|
|
|
|
|
114
|
3
|
|
|
|
|
7
|
$seen{$copy} = 1; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
3
|
|
|
|
|
8
|
$UserDefinedAlias{$alias} = $code; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub remove_alias { |
122
|
1
|
|
|
1
|
0
|
2
|
shift; |
123
|
|
|
|
|
|
|
|
124
|
1
|
|
|
|
|
2
|
%LoadCache = (); |
125
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
13
|
my $alias = shift; |
127
|
|
|
|
|
|
|
|
128
|
1
|
|
|
|
|
6
|
return delete $UserDefinedAlias{$alias}; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# deprecated |
132
|
|
|
|
|
|
|
sub ids { |
133
|
0
|
|
|
0
|
0
|
0
|
shift->codes; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
## no critic (Variables::ProhibitPackageVars) |
137
|
|
|
|
|
|
|
sub codes { |
138
|
|
|
|
|
|
|
wantarray |
139
|
2
|
50
|
|
2
|
1
|
1657
|
? keys %DateTime::Locale::Data::Codes |
140
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::Codes ]; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub names { |
144
|
|
|
|
|
|
|
wantarray |
145
|
1
|
50
|
|
1
|
1
|
221
|
? keys %DateTime::Locale::Data::Names |
146
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::Names ]; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub native_names { |
150
|
|
|
|
|
|
|
wantarray |
151
|
0
|
0
|
|
0
|
1
|
0
|
? keys %DateTime::Locale::Data::NativeNames |
152
|
|
|
|
|
|
|
: [ keys %DateTime::Locale::Data::NativeNames ]; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# These are hard-coded for backwards comaptibility with the DateTime::Language |
156
|
|
|
|
|
|
|
# code. |
157
|
|
|
|
|
|
|
my %DateTimeLanguageAliases = ( |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# 'Afar' => 'aa', |
160
|
|
|
|
|
|
|
'Amharic' => 'am-ET', |
161
|
|
|
|
|
|
|
'Austrian' => 'de-AT', |
162
|
|
|
|
|
|
|
'Brazilian' => 'pt-BR', |
163
|
|
|
|
|
|
|
'Czech' => 'cs-CZ', |
164
|
|
|
|
|
|
|
'Danish' => 'da-DK', |
165
|
|
|
|
|
|
|
'Dutch' => 'nl-NL', |
166
|
|
|
|
|
|
|
'English' => 'en-US', |
167
|
|
|
|
|
|
|
'French' => 'fr-FR', |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# 'Gedeo' => undef, # XXX |
170
|
|
|
|
|
|
|
'German' => 'de-DE', |
171
|
|
|
|
|
|
|
'Italian' => 'it-IT', |
172
|
|
|
|
|
|
|
'Norwegian' => 'no-NO', |
173
|
|
|
|
|
|
|
'Oromo' => 'om-ET', # Maybe om-KE or plain om ? |
174
|
|
|
|
|
|
|
'Portugese' => 'pt-PT', |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# 'Sidama' => 'sid', |
177
|
|
|
|
|
|
|
'Somali' => 'so-SO', |
178
|
|
|
|
|
|
|
'Spanish' => 'es-ES', |
179
|
|
|
|
|
|
|
'Swedish' => 'sv-SE', |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# 'Tigre' => 'tig', |
182
|
|
|
|
|
|
|
'TigrinyaEthiopian' => 'ti-ET', |
183
|
|
|
|
|
|
|
'TigrinyaEritrean' => 'ti-ER', |
184
|
|
|
|
|
|
|
); |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
my %POSIXAliases = ( |
187
|
|
|
|
|
|
|
C => 'en-US', |
188
|
|
|
|
|
|
|
POSIX => 'en-US', |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
{ |
192
|
|
|
|
|
|
|
my $validator = validation_for( |
193
|
|
|
|
|
|
|
name => '_check_load_params', |
194
|
|
|
|
|
|
|
name_is_optional => 1, |
195
|
|
|
|
|
|
|
params => [ |
196
|
|
|
|
|
|
|
{ type => t('NonEmptyStr') }, |
197
|
|
|
|
|
|
|
], |
198
|
|
|
|
|
|
|
); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub load { |
201
|
1070
|
|
|
1070
|
1
|
4080602
|
my $class = shift; |
202
|
1070
|
|
|
|
|
24234
|
my ($code) = $validator->(@_); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# We used to use underscores in codes instead of dashes. We want to |
205
|
|
|
|
|
|
|
# support both indefinitely. |
206
|
1070
|
|
|
|
|
11823
|
$code =~ tr/_/-/; |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Strip off charset for LC_* codes : en_GB.UTF-8 etc |
209
|
1070
|
|
|
|
|
2135
|
$code =~ s/\..*$//; |
210
|
|
|
|
|
|
|
|
211
|
1070
|
100
|
|
|
|
2984
|
return $LoadCache{$code} if exists $LoadCache{$code}; |
212
|
|
|
|
|
|
|
|
213
|
1059
|
|
|
|
|
2297
|
while ( exists $UserDefinedAlias{$code} ) { |
214
|
3
|
|
|
|
|
7
|
$code = $UserDefinedAlias{$code}; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$code = $DateTimeLanguageAliases{$code} |
218
|
1059
|
100
|
|
|
|
2222
|
if exists $DateTimeLanguageAliases{$code}; |
219
|
1059
|
100
|
|
|
|
1864
|
$code = $POSIXAliases{$code} if exists $POSIXAliases{$code}; |
220
|
|
|
|
|
|
|
$code = $DateTime::Locale::Data::ISO639Aliases{$code} |
221
|
1059
|
100
|
|
|
|
2489
|
if exists $DateTime::Locale::Data::ISO639Aliases{$code}; |
222
|
|
|
|
|
|
|
|
223
|
1059
|
100
|
|
|
|
2488
|
if ( exists $DateTime::Locale::Data::Codes{$code} ) { |
224
|
1040
|
|
|
|
|
2590
|
return $class->_locale_object_for($code); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
19
|
100
|
|
|
|
60
|
if ( exists $DateTime::Locale::Data::Names{$code} ) { |
228
|
|
|
|
|
|
|
return $class->_locale_object_for( |
229
|
4
|
|
|
|
|
24
|
$DateTime::Locale::Data::Names{$code} ); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
15
|
100
|
|
|
|
56
|
if ( exists $DateTime::Locale::Data::NativeNames{$code} ) { |
233
|
|
|
|
|
|
|
return $class->_locale_object_for( |
234
|
1
|
|
|
|
|
38
|
$DateTime::Locale::Data::NativeNames{$code} ); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
14
|
100
|
|
|
|
41
|
if ( my $locale = $class->_registered_locale_for($code) ) { |
238
|
7
|
|
|
|
|
19
|
return $locale; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
7
|
100
|
|
|
|
17
|
if ( my $guessed = $class->_guess_code($code) ) { |
242
|
5
|
|
|
|
|
10
|
return $class->_locale_object_for($guessed); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
2
|
|
|
|
|
13
|
die "Invalid locale code or name: $code\n"; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub _guess_code { |
250
|
7
|
|
|
7
|
|
7
|
shift; |
251
|
7
|
|
|
|
|
11
|
my $code = shift; |
252
|
|
|
|
|
|
|
|
253
|
7
|
|
|
|
|
27
|
my %codes = parse_locale_code($code); |
254
|
|
|
|
|
|
|
|
255
|
7
|
|
|
|
|
12
|
my @guesses; |
256
|
|
|
|
|
|
|
|
257
|
7
|
100
|
|
|
|
28
|
if ( $codes{script} ) { |
258
|
1
|
|
|
|
|
3
|
my $guess = join q{-}, $codes{language}, $codes{script}; |
259
|
|
|
|
|
|
|
|
260
|
1
|
|
|
|
|
3
|
push @guesses, $guess; |
261
|
|
|
|
|
|
|
|
262
|
1
|
50
|
|
|
|
3
|
$guess .= q{-} . $codes{territory} if defined $codes{territory}; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# version with script comes first |
265
|
1
|
|
|
|
|
2
|
unshift @guesses, $guess; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
7
|
50
|
|
|
|
43
|
if ( $codes{variant} ) { |
269
|
|
|
|
|
|
|
push @guesses, join q{-}, $codes{language}, $codes{territory}, |
270
|
0
|
|
|
|
|
0
|
$codes{variant}; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
7
|
100
|
|
|
|
16
|
if ( $codes{territory} ) { |
274
|
4
|
|
|
|
|
28
|
push @guesses, join q{-}, $codes{language}, $codes{territory}; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
7
|
|
|
|
|
15
|
push @guesses, $codes{language}; |
278
|
|
|
|
|
|
|
|
279
|
7
|
|
|
|
|
15
|
for my $code (@guesses) { |
280
|
|
|
|
|
|
|
return $code |
281
|
|
|
|
|
|
|
if exists $DateTime::Locale::Data::Codes{$code} |
282
|
7
|
100
|
66
|
|
|
45
|
|| exists $DateTime::Locale::Data::Names{$code}; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub _locale_object_for { |
287
|
1050
|
|
|
1050
|
|
1409
|
shift; |
288
|
1050
|
|
|
|
|
1581
|
my $code = shift; |
289
|
|
|
|
|
|
|
|
290
|
1050
|
50
|
|
|
|
2896
|
my $data = DateTime::Locale::Data::locale_data($code) |
291
|
|
|
|
|
|
|
or return; |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# We want to make a copy of the data just in case ... |
294
|
1050
|
|
|
|
|
1593
|
return $LoadCache{$code} = DateTime::Locale::FromData->new( \%{$data} ); |
|
1050
|
|
|
|
|
6044
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub _registered_locale_for { |
298
|
14
|
|
|
14
|
|
25
|
my $class = shift; |
299
|
14
|
|
|
|
|
23
|
my $code = shift; |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# Custom locale registered by user |
302
|
14
|
100
|
|
|
|
33
|
if ( $Class{$code} ) { |
303
|
|
|
|
|
|
|
return $LoadCache{$code} |
304
|
2
|
|
|
|
|
7
|
= $class->_load_class_from_code( $code, $Class{$code} ); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
12
|
100
|
|
|
|
25
|
if ( $DataForCode{$code} ) { |
308
|
5
|
|
|
|
|
12
|
return $LoadCache{$code} = $class->_load_class_from_code($code); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
7
|
50
|
|
|
|
13
|
if ( $NameToCode{$code} ) { |
312
|
|
|
|
|
|
|
return $LoadCache{$code} |
313
|
0
|
|
|
|
|
0
|
= $class->_load_class_from_code( $NameToCode{$code} ); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
7
|
50
|
|
|
|
23
|
if ( $NativeNameToCode{$code} ) { |
317
|
|
|
|
|
|
|
return $LoadCache{$code} |
318
|
0
|
|
|
|
|
0
|
= $class->_load_class_from_code( $NativeNameToCode{$code} ); |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub _load_class_from_code { |
323
|
7
|
|
|
7
|
|
11
|
my $class = shift; |
324
|
7
|
|
|
|
|
11
|
my $code = shift; |
325
|
7
|
|
|
|
|
9
|
my $real_class = shift; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# We want the first alias for which there is data, even if it has |
328
|
|
|
|
|
|
|
# no corresponding .pm file. There may be multiple levels of |
329
|
|
|
|
|
|
|
# alias to go through. |
330
|
7
|
|
|
|
|
11
|
my $data_code = $code; |
331
|
7
|
|
33
|
|
|
18
|
while ( exists $UserDefinedAlias{$data_code} |
332
|
|
|
|
|
|
|
&& !exists $DataForCode{$data_code} ) { |
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
0
|
$data_code = $UserDefinedAlias{$data_code}; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
7
|
|
|
|
|
26
|
( my $underscore_code = $data_code ) =~ s/-/_/g; |
338
|
7
|
|
66
|
|
|
32
|
$real_class ||= "DateTime::Locale::$underscore_code"; |
339
|
|
|
|
|
|
|
|
340
|
7
|
50
|
|
|
|
92
|
unless ( $real_class->can('new') ) { |
341
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval) |
342
|
0
|
|
|
|
|
0
|
eval "require $real_class"; |
343
|
0
|
0
|
|
|
|
0
|
die $@ if $@; |
344
|
|
|
|
|
|
|
## use critic |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
my $locale = $real_class->new( |
348
|
7
|
|
|
|
|
10
|
%{ $DataForCode{$data_code} }, |
|
7
|
|
|
|
|
39
|
|
349
|
|
|
|
|
|
|
code => $code, |
350
|
|
|
|
|
|
|
); |
351
|
|
|
|
|
|
|
|
352
|
7
|
100
|
|
|
|
49
|
if ( $locale->can('cldr_version') ) { |
353
|
1
|
|
|
|
|
3
|
my $object_version = $locale->cldr_version; |
354
|
|
|
|
|
|
|
|
355
|
1
|
50
|
|
|
|
8
|
if ( $object_version ne $DateTime::Locale::Data::CLDRVersion ) { |
356
|
1
|
|
|
|
|
12
|
warn |
357
|
|
|
|
|
|
|
"Loaded $real_class, which is from an older version ($object_version)" |
358
|
|
|
|
|
|
|
. ' of the CLDR database than this installation of' |
359
|
|
|
|
|
|
|
. " DateTime::Locale ($DateTime::Locale::Data::CLDRVersion).\n"; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
7
|
|
|
|
|
60
|
return $locale; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
## use critic |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
1; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# ABSTRACT: Localization support for DateTime.pm |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
__END__ |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=pod |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=encoding UTF-8 |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 NAME |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
DateTime::Locale - Localization support for DateTime.pm |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 VERSION |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
version 1.38 |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 SYNOPSIS |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
use DateTime::Locale; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
my $loc = DateTime::Locale->load('en-GB'); |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
print $loc->native_name, "\n", $loc->datetime_format_long, "\n"; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# but mostly just things like ... |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my $dt = DateTime->now( locale => 'fr' ); |
396
|
|
|
|
|
|
|
print "Aujourd'hui le mois est " . $dt->month_name, "\n"; |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=head1 DESCRIPTION |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
DateTime::Locale is primarily a factory for the various locale subclasses. It |
401
|
|
|
|
|
|
|
also provides some functions for getting information on all the available |
402
|
|
|
|
|
|
|
locales. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
If you want to know what methods are available for locale objects, then please |
405
|
|
|
|
|
|
|
read the L<DateTime::Locale::FromData> documentation. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head1 USAGE |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
This module provides the following class methods: |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=head2 DateTime::Locale->load( $locale_code | $locale_name ) |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
Returns the locale object for the specified locale code or name - see the |
414
|
|
|
|
|
|
|
L<DateTime::Locale::Catalog> documentation for the list of available codes and |
415
|
|
|
|
|
|
|
names. The name provided may be either the English or native name. |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
If the requested locale is not found, a fallback search takes place to find a |
418
|
|
|
|
|
|
|
suitable replacement. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
The fallback search order is: |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
{language}-{script}-{territory} |
423
|
|
|
|
|
|
|
{language}-{script} |
424
|
|
|
|
|
|
|
{language}-{territory}-{variant} |
425
|
|
|
|
|
|
|
{language}-{territory} |
426
|
|
|
|
|
|
|
{language} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Eg. For the locale code C<es-XX-UNKNOWN> the fallback search would be: |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
es-XX-UNKNOWN # Fails - no such locale |
431
|
|
|
|
|
|
|
es-XX # Fails - no such locale |
432
|
|
|
|
|
|
|
es # Found - the es locale is returned as the |
433
|
|
|
|
|
|
|
# closest match to the requested id |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Eg. For the locale code C<es-Latn-XX> the fallback search would be: |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
es-Latn-XX # Fails - no such locale |
438
|
|
|
|
|
|
|
es-Latn # Fails - no such locale |
439
|
|
|
|
|
|
|
es-XX # Fails - no such locale |
440
|
|
|
|
|
|
|
es # Found - the es locale is returned as the |
441
|
|
|
|
|
|
|
# closest match to the requested id |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
If no suitable replacement is found, then an exception is thrown. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
The loaded locale is cached, so that B<locale objects may be singletons>. |
446
|
|
|
|
|
|
|
Calling C<< DateTime::Locale->register_from_data >>, C<< |
447
|
|
|
|
|
|
|
DateTime::Locale->add_aliases >>, or C<< DateTime::Locale->remove_alias >> |
448
|
|
|
|
|
|
|
clears the cache. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=head2 DateTime::Locale->codes |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
my @codes = DateTime::Locale->codes; |
453
|
|
|
|
|
|
|
my $codes = DateTime::Locale->codes; |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Returns an unsorted list of the available locale codes, or an array reference |
456
|
|
|
|
|
|
|
if called in a scalar context. This list does not include aliases. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=head2 DateTime::Locale->names |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
my @names = DateTime::Locale->names; |
461
|
|
|
|
|
|
|
my $names = DateTime::Locale->names; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Returns an unsorted list of the available locale names in English, or an array |
464
|
|
|
|
|
|
|
reference if called in a scalar context. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head2 DateTime::Locale->native_names |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
my @names = DateTime::Locale->native_names; |
469
|
|
|
|
|
|
|
my $names = DateTime::Locale->native_names; |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Returns an unsorted list of the available locale names in their native |
472
|
|
|
|
|
|
|
language, or an array reference if called in a scalar context. All native names |
473
|
|
|
|
|
|
|
use UTF-8 as appropriate. |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 DateTime::Locale->register_from_data( $locale_data ) |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
This method allows you to register a custom locale. The data for the locale is |
478
|
|
|
|
|
|
|
specified as a hash (or hashref) where the keys match the method names given in |
479
|
|
|
|
|
|
|
L<DateTime::Locale::FromData>. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
If you just want to make some small changes on top of an existing locale you |
482
|
|
|
|
|
|
|
can get that locale's data by calling C<< $locale->locale_data >>. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Here is an example of making a custom locale based off of C<en-US>: |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
my $locale = DateTime::Locale->load('en-US'); |
487
|
|
|
|
|
|
|
my %data = $locale->locale_data; |
488
|
|
|
|
|
|
|
$data{code} = 'en-US-CUSTOM'; |
489
|
|
|
|
|
|
|
$data{time_format_medium} = 'HH:mm:ss'; |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
DateTime::Locale->register_from_data(%data); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Prints 18:24:38 |
494
|
|
|
|
|
|
|
say DateTime->now( locale => 'en-US-CUSTOM' )->strftime('%X'); |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# Prints 6:24:38 PM |
497
|
|
|
|
|
|
|
say DateTime->now( locale => 'en-US' )->strftime('%X'); |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
The keys that should be present in the hash are the same as the accessor |
500
|
|
|
|
|
|
|
methods provided by L<DateTime::Locale::FromData>, except for the following: |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=over 4 |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=item The C<*_code> methods |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
While you should provide a C<code> key, the other methods like C<language_code> |
507
|
|
|
|
|
|
|
and C<script_code> are determined by parsing the code. |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=item All C<id> returning methods |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
These are aliases for the corresponding C<*code> methods. |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item C<prefers_24_hour_time> |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
This is determined by looking at the short time format to see how it formats |
516
|
|
|
|
|
|
|
hours, |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item C<date_format_default> and C<time_format_default> |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
These are the corresponding medium formats. |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=item C<datetime_format> and C<datetime_format_default> |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
This is the same as the medium format. |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=item C<date_formats> and C<time_formats> |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
These are calculated as needed. |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=item C<available_formats> |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
This should be provided as a hashref where the keys are things like C<Gy> or |
533
|
|
|
|
|
|
|
C<MMMEd> and the values are an actual format like C<"y G"> or C<"E, MMM d">. |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=item C<locale_data> |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
This is everything you pass in. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=back |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head1 LOADING LOCALES IN A PRE-FORKING SYSTEM |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
If you are running an application that does pre-forking (for example with |
544
|
|
|
|
|
|
|
Starman), then you should try to load all the locales that you'll need in the |
545
|
|
|
|
|
|
|
parent process. Locales are loaded on-demand, so loading them once in each |
546
|
|
|
|
|
|
|
child will waste memory that could otherwise be shared. |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head1 CLDR DATA BUGS |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
Please be aware that all locale data has been generated from the CLDR (Common |
551
|
|
|
|
|
|
|
Locale Data Repository) project locales data). The data is incomplete, and may |
552
|
|
|
|
|
|
|
contain errors in some locales. |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
When reporting errors in data, please check the primary data sources first, |
555
|
|
|
|
|
|
|
then where necessary report errors directly to the primary source via the CLDR |
556
|
|
|
|
|
|
|
bug report system. See L<http://unicode.org/cldr/filing_bug_reports.html> for |
557
|
|
|
|
|
|
|
details. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
Once these errors have been confirmed, please forward the error report and |
560
|
|
|
|
|
|
|
corrections to the DateTime mailing list, datetime@perl.org. |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head1 AUTHOR EMERITUS |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
Richard Evans wrote the first version of DateTime::Locale, including the tools |
565
|
|
|
|
|
|
|
to extract the CLDR data. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=head1 SEE ALSO |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
datetime@perl.org mailing list |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head1 SUPPORT |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
Bugs may be submitted at L<https://github.com/houseabsolute/DateTime-Locale/issues>. |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
There is a mailing list available for users of this distribution, |
576
|
|
|
|
|
|
|
L<mailto:datetime@perl.org>. |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=head1 SOURCE |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
The source code repository for DateTime-Locale can be found at L<https://github.com/houseabsolute/DateTime-Locale>. |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head1 DONATIONS |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
If you'd like to thank me for the work I've done on this module, please |
585
|
|
|
|
|
|
|
consider making a "donation" to me via PayPal. I spend a lot of free time |
586
|
|
|
|
|
|
|
creating free software, and would appreciate any support you'd care to offer. |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
Please note that B<I am not suggesting that you must do this> in order for me |
589
|
|
|
|
|
|
|
to continue working on this particular software. I will continue to do so, |
590
|
|
|
|
|
|
|
inasmuch as I have in the past, for as long as it interests me. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Similarly, a donation made in this way will probably not make me work on this |
593
|
|
|
|
|
|
|
software much more, unless I get so many donations that I can consider working |
594
|
|
|
|
|
|
|
on free software full time (let's all have a chuckle at that together). |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
To donate, log into PayPal and send money to autarch@urth.org, or use the |
597
|
|
|
|
|
|
|
button at L<https://houseabsolute.com/foss-donations/>. |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=head1 AUTHOR |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
Dave Rolsky <autarch@urth.org> |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=for stopwords Alexander Pankoff James Raspass Karen Etheridge Mohammad S Anwar Ryley Breiddal Sergey Leschenko yasu47b |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=over 4 |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=item * |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
Alexander Pankoff <ccntrq@screenri.de> |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=item * |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
James Raspass <jraspass@gmail.com> |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=item * |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
Karen Etheridge <ether@cpan.org> |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=item * |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
Mohammad S Anwar <mohammad.anwar@yahoo.com> |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=item * |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
Ryley Breiddal <rbreiddal@presinet.com> |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=item * |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
Sergey Leschenko <Sergey.Leschenko@portaone.com> |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
=item * |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
yasu47b <nakayamayasuhiro1986@gmail.com> |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=back |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
This software is copyright (c) 2003 - 2023 by Dave Rolsky. |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
644
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
The full text of the license can be found in the |
647
|
|
|
|
|
|
|
F<LICENSE> file included with this distribution. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=cut |