|
0 |
package _locales_build_utils;
|
|
1 |
|
|
2 |
use Cwd;
|
|
3 |
use XML::Simple;
|
|
4 |
use XML::Twig;
|
|
5 |
use File::Path::Tiny;
|
|
6 |
use lib Cwd::realpath('lib');
|
|
7 |
use Locales;
|
|
8 |
use File::Slurp;
|
|
9 |
use Encode (); # to be stringified properly from hash value bug: s{\|\|\s*(\$fallback_lang_misc_info\-\>\S*)\,}{|| Encode::decode_utf8($1),}
|
|
10 |
use String::Unquotemeta;
|
|
11 |
use JSON::Syck;
|
|
12 |
use JavaScript::Minifier::XS;
|
|
13 |
|
|
14 |
#### this ugliness will be spruced up when we go to CLDR-via-JSON in rt 69340 (no XML voo doo and we can move to TT for mod building) ##
|
|
15 |
|
|
16 |
# datetime.json
|
|
17 |
our $tripped;
|
|
18 |
use Test::Carp sub { $tripped = 1 if $_[0]; };
|
|
19 |
use DateTime::Locale;
|
|
20 |
use Class::Inspector;
|
|
21 |
my $en_dt_loc = DateTime::Locale->load('en');
|
|
22 |
my @dt_methods;
|
|
23 |
for my $meth ( @{ Class::Inspector->methods( ref($en_dt_loc), "public" ) } ) {
|
|
24 |
next if $meth eq 'new' || $meth eq 'carp' || $meth eq 'format_for' || $meth eq 'validate_pos';
|
|
25 |
next if $meth =~ m/^(:?set_|STORABLE_)/;
|
|
26 |
|
|
27 |
*DateTime::Locale::Base::carp = sub { Carp::carp( $_[0] ) };
|
|
28 |
local $tripped = 0;
|
|
29 |
Test::Carp::does_carp_that_matches(
|
|
30 |
sub {
|
|
31 |
eval { $en_dt_loc->$meth() };
|
|
32 |
},
|
|
33 |
qr/The $meth method in DateTime::Locale::Base has been deprecated/
|
|
34 |
);
|
|
35 |
next if $tripped;
|
|
36 |
|
|
37 |
push @dt_methods, $meth;
|
|
38 |
}
|
|
39 |
my @dt_available_formats = $en_dt_loc->available_formats();
|
|
40 |
|
|
41 |
# /datetime.json
|
|
42 |
|
|
43 |
use Hash::Merge;
|
|
44 |
Hash::Merge::specify_behavior(
|
|
45 |
{
|
|
46 |
'SCALAR' => {
|
|
47 |
'SCALAR' => sub { !defined $_[0] ? $_[1] : $_[0] },
|
|
48 |
'ARRAY' => sub { !defined $_[0] ? $_[1] : $_[0] },
|
|
49 |
'HASH' => sub { !defined $_[0] ? $_[1] : $_[0] },
|
|
50 |
},
|
|
51 |
'ARRAY' => {
|
|
52 |
'SCALAR' => sub { defined $_[0] ? $_[0] : [ @{ $_[0] }, $_[1] ] },
|
|
53 |
'ARRAY' => sub { defined $_[0] ? $_[0] : [ @{ $_[0] }, @{ $_[1] } ] },
|
|
54 |
'HASH' => sub { defined $_[0] ? $_[0] : [ @{ $_[0] }, values %{ $_[1] } ] },
|
|
55 |
},
|
|
56 |
'HASH' => {
|
|
57 |
'SCALAR' => sub { $_[0] },
|
|
58 |
'ARRAY' => sub { $_[0] },
|
|
59 |
'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
|
|
60 |
},
|
|
61 |
},
|
|
62 |
"left undef/missing"
|
|
63 |
);
|
|
64 |
|
|
65 |
sub merge_hash {
|
|
66 |
goto &Hash::Merge::merge;
|
|
67 |
}
|
|
68 |
use Data::Dumper;
|
|
69 |
$Data::Dumper::Terse = 1;
|
|
70 |
$Data::Dumper::Sortkeys = 1;
|
|
71 |
$Data::Dumper::Useqq = 1;
|
|
72 |
{
|
|
73 |
no warnings 'redefine';
|
|
74 |
|
|
75 |
sub Data::Dumper::qquote {
|
|
76 |
my $s = shift;
|
|
77 |
my $q = quotemeta($s);
|
|
78 |
return $s ne $q ? qq{"$q"} : qq{'$s'};
|
|
79 |
}
|
|
80 |
}
|
|
81 |
|
|
82 |
my $v_offset = '0.24';
|
|
83 |
my $mod_version = $Locales::VERSION - $v_offset;
|
|
84 |
my $cldr_version = $Locales::cldr_version;
|
|
85 |
my $cldr_db_path;
|
|
86 |
my $locales_db;
|
|
87 |
my $manifest;
|
|
88 |
our $plural_forms;
|
|
89 |
|
|
90 |
sub init_paths_from_argv {
|
|
91 |
die "no CLDR path given" if !-d "$ARGV[0]/common/main";
|
|
92 |
$cldr_db_path = Cwd::realpath( $ARGV[0] ) || die "need path to CLDR";
|
|
93 |
$locales_db = Cwd::realpath( $SARGV[1] || 'lib/Locales/DB' );
|
|
94 |
$manifest = Cwd::realpath( $SARGV[2] || 'MANIFEST.build' );
|
|
95 |
|
|
96 |
my $plural_forms_xml = XMLin( "$ARGV[0]/common/supplemental/plurals.xml", ForceArray => 1 ); # ,'KeyAttr' => {'pluralRules' => '+locales' });
|
|
97 |
for my $plural ( @{ $plural_forms_xml->{'plurals'}[0]{'pluralRules'} } ) {
|
|
98 |
for my $loc ( split( /\s+/, $plural->{'locales'} ) ) {
|
|
99 |
$plural_forms->{$loc} = { map { $_->{'count'} => $_->{'content'} } @{ $plural->{'pluralRule'} } };
|
|
100 |
if ( !keys %{ $plural_forms->{$loc} } ) {
|
|
101 |
$plural_forms->{$loc} = undef();
|
|
102 |
}
|
|
103 |
}
|
|
104 |
}
|
|
105 |
|
|
106 |
# print Dumper($plural_forms);die; # _xml->{'plurals'}[0]{'pluralRules'});die;
|
|
107 |
|
|
108 |
return ( $cldr_db_path, $locales_db, $manifest );
|
|
109 |
}
|
|
110 |
|
|
111 |
sub get_xml_file_for {
|
|
112 |
my ( $tag, $quiet ) = @_;
|
|
113 |
my $xml_file = "$cldr_db_path/common/main/$tag.xml";
|
|
114 |
if ( !-e $xml_file ) {
|
|
115 |
warn "\t1) No $xml_file ...\n" if !$quiet;
|
|
116 |
my $tag_copy = $tag;
|
|
117 |
$tag_copy =~ s{_(\w+)$}{_\U$1\E};
|
|
118 |
$xml_file = "$cldr_db_path/common/main/$tag_copy.xml";
|
|
119 |
if ( !-e $xml_file ) {
|
|
120 |
warn "\t2) No $xml_file ...\n" if !$quiet;
|
|
121 |
$tag_copy =~ tr/a-z/A-Z/;
|
|
122 |
$xml_file = "$cldr_db_path/common/main/$tag_copy.xml";
|
|
123 |
if ( !-e $xml_file ) {
|
|
124 |
warn "\t3) No $xml_file ...\n" if !$quiet;
|
|
125 |
return;
|
|
126 |
}
|
|
127 |
}
|
|
128 |
}
|
|
129 |
return $xml_file;
|
|
130 |
|
|
131 |
}
|
|
132 |
|
|
133 |
sub get_target_structs_from_cldr_for_tag {
|
|
134 |
my ( $tag, $fallback_lang_code_to_name, $fallback_terr_code_to_name, $fallback_lang_misc_info ) = @_;
|
|
135 |
|
|
136 |
# if ( $tag eq 'pt_br' ) { print Dumper( [ 'get_target_structs_from_cldr_for_tag', $fallback_lang_misc_info ] ) }
|
|
137 |
my $xml_file = get_xml_file_for($tag);
|
|
138 |
return if !-e $xml_file;
|
|
139 |
|
|
140 |
print "Loading $tag XML from $xml_file...\n";
|
|
141 |
|
|
142 |
# my $raw_struct = XMLin($xml_file, 'KeyAttr' => 'type');
|
|
143 |
my $raw_struct = XML::Twig->new()->parsefile($xml_file)->simplify(
|
|
144 |
'keyattr' => {
|
|
145 |
'codePattern' => '+type',
|
|
146 |
'listPatternPart' => '+type',
|
|
147 |
'characters' => '+type',
|
|
148 |
'ellipsis' => '+type',
|
|
149 |
'territory' => '+type',
|
|
150 |
'language' => '+type',
|
|
151 |
}
|
|
152 |
);
|
|
153 |
|
|
154 |
my ( $lang_code_to_name, $lang_name_to_code, $lang_misc_info, $terr_code_to_name, $terr_name_to_code ) = ( {}, {}, {}, {}, {} );
|
|
155 |
|
|
156 |
#### Territories ####
|
|
157 |
for my $trr ( keys %{ $raw_struct->{'localeDisplayNames'}{'territories'}{'territory'} } ) {
|
|
158 |
|
|
159 |
# Do not skip ISO 3166-1-numeric (e.g. 419, as in es_419)
|
|
160 |
# next if $trr =~ m/^\d+$/;
|
|
161 |
|
|
162 |
my $short = $trr;
|
|
163 |
$short =~ tr/A-Z/a-z/;
|
|
164 |
|
|
165 |
$terr_code_to_name->{$short} = $raw_struct->{'localeDisplayNames'}{'territories'}{'territory'}{$trr}{'content'};
|
|
166 |
$terr_name_to_code->{ Locales::normalize_for_key_lookup( $raw_struct->{'localeDisplayNames'}{'territories'}{'territory'}{$trr}{'content'} ) } = $short;
|
|
167 |
}
|
|
168 |
|
|
169 |
if ($fallback_terr_code_to_name) {
|
|
170 |
for my $fb_trr ( keys %{$fallback_terr_code_to_name} ) {
|
|
171 |
if ( !exists $terr_code_to_name->{$fb_trr} ) {
|
|
172 |
$terr_code_to_name->{$fb_trr} = $fallback_terr_code_to_name->{$fb_trr};
|
|
173 |
$terr_name_to_code->{ Locales::normalize_for_key_lookup( $fallback_terr_code_to_name->{$fb_trr} ) } = $fb_trr;
|
|
174 |
}
|
|
175 |
}
|
|
176 |
}
|
|
177 |
#### /Territories ####
|
|
178 |
|
|
179 |
#### Languages ####
|
|
180 |
my $fallback = undef; # or [] ?
|
|
181 |
if ( exists $raw_struct->{'fallback'} ) {
|
|
182 |
$fallback = [];
|
|
183 |
if ( my $type = ref( $raw_struct->{'fallback'} ) ) {
|
|
184 |
if ( $type eq 'ARRAY' ) {
|
|
185 |
for my $fb ( @{ $raw_struct->{'fallback'} } ) {
|
|
186 |
my $thing = ref($fb) ? $fb->{'content'} : $fb;
|
|
187 |
next if !defined $thing;
|
|
188 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $thing );
|
|
189 |
}
|
|
190 |
}
|
|
191 |
elsif ( $type eq 'HASH' ) {
|
|
192 |
if ( $raw_struct->{'fallback'}{'content'} ) {
|
|
193 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $raw_struct->{'fallback'}{'content'} );
|
|
194 |
}
|
|
195 |
}
|
|
196 |
}
|
|
197 |
else {
|
|
198 |
if ( $raw_struct->{'fallback'} ) {
|
|
199 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $raw_struct->{'fallback'} );
|
|
200 |
}
|
|
201 |
}
|
|
202 |
}
|
|
203 |
elsif ( exists $fallback_lang_misc_info->{'fallback'} ) {
|
|
204 |
$fallback = [];
|
|
205 |
if ( my $type = ref( $fallback_lang_misc_info->{'fallback'} ) ) {
|
|
206 |
if ( $type eq 'ARRAY' ) {
|
|
207 |
for my $fb ( @{ $fallback_lang_misc_info->{'fallback'} } ) {
|
|
208 |
my $thing = ref($fb) ? $fb->{'content'} : $fb;
|
|
209 |
next if !defined $thing;
|
|
210 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $thing );
|
|
211 |
}
|
|
212 |
}
|
|
213 |
elsif ( $type eq 'HASH' ) {
|
|
214 |
if ( $fallback_lang_misc_info->{'fallback'}{'content'} ) {
|
|
215 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $fallback_lang_misc_info->{'fallback'}{'content'} );
|
|
216 |
}
|
|
217 |
}
|
|
218 |
}
|
|
219 |
else {
|
|
220 |
if ( $fallback_lang_misc_info->{'fallback'} ) {
|
|
221 |
push @{$fallback}, map { Locales::normalize_tag("$_") } split( /\s+/, $fallback_lang_misc_info->{'fallback'} );
|
|
222 |
}
|
|
223 |
}
|
|
224 |
}
|
|
225 |
|
|
226 |
my $symbols_index;
|
|
227 |
if ( ref( $raw_struct->{'numbers'}{'symbols'} ) eq 'ARRAY' ) {
|
|
228 |
my $default_numbersystem = $raw_struct->{'numbers'}{'defaultNumberingSystem'} || $raw_struct->{'numbers'}{'defaultNumberingSystem'} || 'latn';
|
|
229 |
if ( ref($default_numbersystem) eq 'HASH' ) {
|
|
230 |
$default_numbersystem = $default_numbersystem->{'content'};
|
|
231 |
}
|
|
232 |
|
|
233 |
my $idx = -1;
|
|
234 |
for my $item ( @{ $raw_struct->{'numbers'}{'symbols'} } ) {
|
|
235 |
$idx++;
|
|
236 |
|
|
237 |
if ( ref($item) eq 'HASH' && $item->{'numberSystem'} eq $default_numbersystem ) {
|
|
238 |
$symbols_index = $idx;
|
|
239 |
last;
|
|
240 |
}
|
|
241 |
}
|
|
242 |
}
|
|
243 |
|
|
244 |
my $_decimal_format_group =
|
|
245 |
defined $symbols_index
|
|
246 |
? (
|
|
247 |
ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'group'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'group'}{'content'}
|
|
248 |
: ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'group'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'group'}->[0]
|
|
249 |
: $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'group'}
|
|
250 |
)
|
|
251 |
: (
|
|
252 |
ref $raw_struct->{'numbers'}{'symbols'}{'group'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}{'group'}{'content'}
|
|
253 |
: ref $raw_struct->{'numbers'}{'symbols'}{'group'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}{'group'}->[0]
|
|
254 |
: $raw_struct->{'numbers'}{'symbols'}{'group'}
|
|
255 |
);
|
|
256 |
if ( ref($_decimal_format_group) eq 'HASH' ) {
|
|
257 |
$_decimal_format_group = $_decimal_format_group->{'content'};
|
|
258 |
}
|
|
259 |
|
|
260 |
my $_decimal_format_decimal = defined $symbols_index
|
|
261 |
? (
|
|
262 |
ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'decimal'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'decimal'}{'content'}
|
|
263 |
: ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'decimal'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'decimal'}->[0]
|
|
264 |
: $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'decimal'}
|
|
265 |
|
|
266 |
)
|
|
267 |
: (
|
|
268 |
ref $raw_struct->{'numbers'}{'symbols'}{'decimal'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}{'decimal'}{'content'}
|
|
269 |
: ref $raw_struct->{'numbers'}{'symbols'}{'decimal'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}{'decimal'}->[0]
|
|
270 |
: $raw_struct->{'numbers'}{'symbols'}{'decimal'}
|
|
271 |
);
|
|
272 |
if ( ref($_decimal_format_decimal) eq 'HASH' ) {
|
|
273 |
$_decimal_format_decimal = $_decimal_format_decimal->{'content'};
|
|
274 |
}
|
|
275 |
|
|
276 |
# only fallback if *both* will match
|
|
277 |
if ( !$_decimal_format_group && !$_decimal_format_decimal ) {
|
|
278 |
$_decimal_format_group = $fallback_lang_misc_info->{'cldr_formats'}{'_decimal_format_group'};
|
|
279 |
$_decimal_format_decimal = $fallback_lang_misc_info->{'cldr_formats'}{'_decimal_format_decimal'};
|
|
280 |
}
|
|
281 |
|
|
282 |
# if we are missing one use both it's parent's data if possible
|
|
283 |
if ( !$_decimal_format_group || !$_decimal_format_decimal ) {
|
|
284 |
my ( $l, $t ) = Locales::split_tag($tag);
|
|
285 |
if ($t) {
|
|
286 |
if ( my $parent = Locales->new($l) ) {
|
|
287 |
no strict 'refs';
|
|
288 |
$_decimal_format_group = ${"Locales::DB::Language::${l}::misc_info"}{'cldr_formats'}->{'_decimal_format_group'};
|
|
289 |
$_decimal_format_decimal = ${"Locales::DB::Language::${l}::misc_info"}{'cldr_formats'}->{'_decimal_format_decimal'};
|
|
290 |
}
|
|
291 |
}
|
|
292 |
}
|
|
293 |
|
|
294 |
if ( !$_decimal_format_group || !$_decimal_format_decimal ) {
|
|
295 |
|
|
296 |
# not much we can (accuratly) do, I am open to suggestions :)
|
|
297 |
warn "'$tag' is missing one or both decimal format options: _decimal_format_group ($_decimal_format_group) or _decimal_format_decimal ($_decimal_format_decimal) ...";
|
|
298 |
if ( $_decimal_format_group eq ',' ) {
|
|
299 |
$_decimal_format_decimal = '.';
|
|
300 |
}
|
|
301 |
elsif ( $_decimal_format_group eq '.' ) {
|
|
302 |
$_decimal_format_decimal = ',';
|
|
303 |
}
|
|
304 |
elsif ( $_decimal_format_decimal eq ',' ) {
|
|
305 |
$_decimal_format_group = '.';
|
|
306 |
}
|
|
307 |
elsif ( $_decimal_format_decimal eq '.' ) {
|
|
308 |
$_decimal_format_group = ',';
|
|
309 |
}
|
|
310 |
|
|
311 |
# TODO: fallback to values in its numberSystem (e.g. <symbols numberSystem="latn">) (only trips up a few as of CLDR 2.0)
|
|
312 |
elsif ( $tag eq 'ak' || $tag eq 'mfe' || $tag eq 'ses' || $tag eq 'khq' || $tag eq 'wal' ) {
|
|
313 |
$_decimal_format_decimal = '.';
|
|
314 |
}
|
|
315 |
|
|
316 |
else {
|
|
317 |
warn "\tCould not make worst-case-best-effort defualt from the curretn value.";
|
|
318 |
}
|
|
319 |
}
|
|
320 |
|
|
321 |
my $_percent_format_percent = (
|
|
322 |
defined $symbols_index
|
|
323 |
? (
|
|
324 |
ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'percentSign'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'percentSign'}{'content'}
|
|
325 |
: ref $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'percentSign'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'percentSign'}->[0]
|
|
326 |
: $raw_struct->{'numbers'}{'symbols'}[$symbols_index]{'percentSign'}
|
|
327 |
)
|
|
328 |
: (
|
|
329 |
ref $raw_struct->{'numbers'}{'symbols'}{'percentSign'} eq 'HASH' ? $raw_struct->{'numbers'}{'symbols'}{'percentSign'}{'content'}
|
|
330 |
: ref $raw_struct->{'numbers'}{'symbols'}{'percentSign'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'symbols'}{'percentSign'}->[0]
|
|
331 |
: $raw_struct->{'numbers'}{'symbols'}{'percentSign'}
|
|
332 |
)
|
|
333 |
)
|
|
334 |
|| $fallback_lang_misc_info->{'cldr_formats'}{'_percent_format_percent'};
|
|
335 |
if ( !$_percent_format_percent ) {
|
|
336 |
my ( $l, $t ) = Locales::split_tag($tag);
|
|
337 |
if ($t) {
|
|
338 |
if ( my $parent = Locales->new($l) ) {
|
|
339 |
no strict 'refs';
|
|
340 |
$_percent_format_percent = ${"Locales::DB::Language::${l}::misc_info"}{'cldr_formats'}->{'_percent_format_percent'};
|
|
341 |
}
|
|
342 |
}
|
|
343 |
}
|
|
344 |
|
|
345 |
# $fallback_lang_misc_info->{'cldr_formats'}{'delimiters'} ||= {
|
|
346 |
# map {
|
|
347 |
# my $norm = $_;
|
|
348 |
# $norm = lcfirst($norm);
|
|
349 |
# $norm =~ s/([A-Z])/_\L$1\E/g;
|
|
350 |
# ($norm => $raw_struct->{'delimiters'}{$_})
|
|
351 |
# } keys %{ $raw_struct->{'delimiters'} }
|
|
352 |
# };
|
|
353 |
|
|
354 |
# if ( $tag eq 'pt_br' ) { use Data::Dumper; print Dumper( $tag, $fallback_lang_misc_info ) }
|
|
355 |
|
|
356 |
# ick
|
|
357 |
if ( ref( $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'} ) eq 'HASH' ) {
|
|
358 |
if ( $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'type'} eq 'short' ) {
|
|
359 |
delete $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'};
|
|
360 |
}
|
|
361 |
}
|
|
362 |
elsif ( ref( $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'} ) eq 'ARRAY' ) {
|
|
363 |
if ( $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'type'} eq 'short' ) {
|
|
364 |
shift @{ $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'} };
|
|
365 |
}
|
|
366 |
}
|
|
367 |
|
|
368 |
my $plural_form_entry = $plural_forms->{$tag};
|
|
369 |
if ( !$plural_form_entry ) {
|
|
370 |
my ($parent_tag) = Locales::split_tag($tag);
|
|
371 |
if ( $parent_tag ne $tag && exists $plural_forms->{$parent_tag} ) {
|
|
372 |
$plural_form_entry = $plural_forms->{$parent_tag};
|
|
373 |
}
|
|
374 |
else {
|
|
375 |
for my $fb ( @{$fallback} ) {
|
|
376 |
if ( exists $plural_forms->{$fb} && ref( $plural_forms->{$fb} ) ) {
|
|
377 |
$plural_form_entry = $plural_forms->{$fb};
|
|
378 |
last;
|
|
379 |
}
|
|
380 |
}
|
|
381 |
}
|
|
382 |
}
|
|
383 |
|
|
384 |
# DO NOT DO THIS: $plural_form_entry ||= $plural_forms->{'en'};
|
|
385 |
|
|
386 |
$lang_misc_info = {
|
|
387 |
'fallback' => $fallback,
|
|
388 |
'cldr_formats' => {
|
|
389 |
'decimal' => (
|
|
390 |
ref( $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'} ) eq 'ARRAY'
|
|
391 |
? (
|
|
392 |
ref $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'decimalFormat'}{'pattern'} eq 'HASH' ? $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'decimalFormat'}{'pattern'}{'content'}
|
|
393 |
: ref $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'decimalFormat'}{'pattern'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'decimalFormat'}{'pattern'}->[0]
|
|
394 |
: $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}[0]{'decimalFormat'}{'pattern'}
|
|
395 |
|
|
396 |
)
|
|
397 |
: (
|
|
398 |
ref $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'decimalFormat'}{'pattern'} eq 'HASH' ? $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'decimalFormat'}{'pattern'}{'content'}
|
|
399 |
: ref $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'decimalFormat'}{'pattern'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'decimalFormat'}{'pattern'}->[0]
|
|
400 |
: $raw_struct->{'numbers'}{'decimalFormats'}{'decimalFormatLength'}{'decimalFormat'}{'pattern'}
|
|
401 |
)
|
|
402 |
)
|
|
403 |
|| Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'decimal'} ),
|
|
404 |
'_decimal_format_group' => $_decimal_format_group,
|
|
405 |
'_decimal_format_decimal' => $_decimal_format_decimal,
|
|
406 |
'percent' => (
|
|
407 |
ref $raw_struct->{'numbers'}{'percentFormats'}{'percentFormatLength'}{'percentFormat'}{'pattern'} eq 'HASH' ? $raw_struct->{'numbers'}{'percentFormats'}{'percentFormatLength'}{'percentFormat'}{'pattern'}{'content'}
|
|
408 |
: ref $raw_struct->{'numbers'}{'percentFormats'}{'percentFormatLength'}{'percentFormat'}{'pattern'} eq 'ARRAY' ? $raw_struct->{'numbers'}{'percentFormats'}{'percentFormatLength'}{'percentFormat'}{'pattern'}->[0]
|
|
409 |
: $raw_struct->{'numbers'}{'percentFormats'}{'percentFormatLength'}{'percentFormat'}{'pattern'}
|
|
410 |
)
|
|
411 |
|| Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'percent'} ),
|
|
412 |
'_percent_format_percent' => $_percent_format_percent,
|
|
413 |
'territory' => $raw_struct->{'localeDisplayNames'}{'codePatterns'}{'codePattern'}{'territory'}{'content'}
|
|
414 |
|| Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'territory'} ),
|
|
415 |
'language' => $raw_struct->{'localeDisplayNames'}{'codePatterns'}{'codePattern'}{'language'}{'content'}
|
|
416 |
|| Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'language'} ),
|
|
417 |
'locale' => ( Encode::decode_utf8( ref( $raw_struct->{'localeDisplayNames'}{'localeDisplayPattern'}{'localePattern'} ) eq 'HASH' ? $raw_struct->{'localeDisplayNames'}{'localeDisplayPattern'}{'localePattern'}{'content'} : $raw_struct->{'localeDisplayNames'}{'localeDisplayPattern'}{'localePattern'} ) )
|
|
418 |
|| Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'locale'} ), # wx_yz has no name but wx does and xy may
|
|
419 |
# {'localeDisplayNames'}{'localeDisplayPattern'}{'localePattern'}{'localeSeparator'} => ', ' (not needed since we only use territory subtag)
|
|
420 |
'list' => {
|
|
421 |
'2' => $raw_struct->{'listPatterns'}{'listPattern'}{'listPatternPart'}{'2'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'list'}{'2'} ),
|
|
422 |
'end' => $raw_struct->{'listPatterns'}{'listPattern'}{'listPatternPart'}{'end'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'list'}{'end'} ),
|
|
423 |
'middle' => $raw_struct->{'listPatterns'}{'listPattern'}{'listPatternPart'}{'middle'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'list'}{'middle'} ),
|
|
424 |
'start' => $raw_struct->{'listPatterns'}{'listPattern'}{'listPatternPart'}{'start'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'list'}{'start'} ),
|
|
425 |
},
|
|
426 |
'ellipsis' => {
|
|
427 |
|
|
428 |
# Encode::decode_utf8() on current fallback will keep from tripping perl's hash value bytes string bug?
|
|
429 |
'final' => $raw_struct->{'characters'}{'ellipsis'}{'final'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'ellipsis'}{'final'} ),
|
|
430 |
'initial' => $raw_struct->{'characters'}{'ellipsis'}{'initial'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'ellipsis'}{'initial'} ),
|
|
431 |
'medial' => $raw_struct->{'characters'}{'ellipsis'}{'medial'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'cldr_formats'}{'ellipsis'}{'medial'} ),
|
|
432 |
},
|
|
433 |
},
|
|
434 |
'characters' => {
|
|
435 |
'more_information' => (
|
|
436 |
ref( $raw_struct->{'characters'}{'moreInformation'} ) eq 'HASH'
|
|
437 |
? ( $raw_struct->{'characters'}{'moreInformation'}{'content'} || Encode::decode_utf8( $fallback_lang_misc_info->{'characters'}{'more_information'} ) )
|
|
438 |
: ( $raw_struct->{'characters'}{'moreInformation'} || Encode::decode_utf8( $fallback_lang_misc_info->{'characters'}{'more_information'} ) )
|
|
439 |
)
|
|
440 |
},
|
|
441 |
'delimiters' => {
|
|
442 |
map {
|
|
443 |
my $norm = $_;
|
|
444 |
$norm = lcfirst($norm);
|
|
445 |
$norm =~ s/([A-Z])/_\L$1\E/g;
|
|
446 |
|
|
447 |
# print Dumper(
|
|
448 |
# [
|
|
449 |
# $_,
|
|
450 |
# $norm,
|
|
451 |
# exists $raw_struct->{'delimiters'}{$_},
|
|
452 |
# $raw_struct->{'delimiters'}{$_},
|
|
453 |
# $fallback_lang_misc_info->{'cldr_formats'}{'delimiters'}{$norm}
|
|
454 |
# ]);
|
|
455 |
(
|
|
456 |
$norm => (
|
|
457 |
exists $raw_struct->{'delimiters'}{$_}
|
|
458 |
? ( $raw_struct->{'delimiters'}{$_} || $fallback_lang_misc_info->{'delimiters'}{$norm} )
|
|
459 |
: $fallback_lang_misc_info->{'delimiters'}{$norm}
|
|
460 |
)
|
|
461 |
)
|
|
462 |
} ( 'quotationStart', 'quotationEnd', 'alternateQuotationStart', 'alternateQuotationEnd' )
|
|
463 |
},
|
|
464 |
'plural_forms' => {
|
|
465 |
|
|
466 |
# Order is important for Locale::Maketext::Utils::quant():
|
|
467 |
# one (singular), two (dual), few (paucal), many, other, zero
|
|
468 |
'category_list' => [
|
|
469 |
(
|
|
470 |
( grep { exists $plural_form_entry->{$_} } ( Locales::get_cldr_plural_category_list() ) ),
|
|
471 |
exists $plural_form_entry->{'other'} ? () : ('other') # has to have 'other' at the end if no where else
|
|
472 |
)
|
|
473 |
],
|
|
474 |
'category_rules' => $plural_form_entry,
|
|
475 |
},
|
|
476 |
'orientation' => {
|
|
477 |
'characters' => $raw_struct->{'layout'}{'orientation'}{'characters'} || $fallback_lang_misc_info->{'orientation'}{'characters'} || 'left-to-right',
|
|
478 |
'lines' => $raw_struct->{'layout'}{'orientation'}{'lines'} || $fallback_lang_misc_info->{'orientation'}{'lines'} || 'top-to-bottom',
|
|
479 |
},
|
|
480 |
'posix' => {
|
|
481 |
'yesstr' => $raw_struct->{'posix'}{'messages'}{'yesstr'} || Encode::decode_utf8( $fallback_lang_misc_info->{'posix'}{'yesstr'} ),
|
|
482 |
'nostr' => $raw_struct->{'posix'}{'messages'}{'nostr'} || Encode::decode_utf8( $fallback_lang_misc_info->{'posix'}{'nostr'} ),
|
|
483 |
|
|
484 |
# TODO: yesexp/noexp
|
|
485 |
},
|
|
486 |
};
|
|
487 |
|
|
488 |
for my $k ( keys %{ $lang_misc_info->{'delimiters'} } ) {
|
|
489 |
if ( ref( $lang_misc_info->{'delimiters'}{$k} ) eq 'HASH' ) {
|
|
490 |
$lang_misc_info->{'delimiters'}{$k} = $lang_misc_info->{'delimiters'}{$k}{'content'};
|
|
491 |
}
|
|
492 |
}
|
|
493 |
|
|
494 |
for my $lng ( sort keys %{ $raw_struct->{'localeDisplayNames'}{'languages'}{'language'} } ) {
|
|
495 |
next if $lng eq 'root';
|
|
496 |
|
|
497 |
# if ($tag eq 'en') {
|
|
498 |
# next if !get_xml_file_for($lng,1);
|
|
499 |
# }
|
|
500 |
|
|
501 |
my $short = $lng;
|
|
502 |
$short =~ tr/A-Z/a-z/;
|
|
503 |
|
|
504 |
my ( $l, $t, @x ) = split( /_/, $short );
|
|
505 |
next if @x;
|
|
506 |
next if $t && !exists $terr_code_to_name->{$t};
|
|
507 |
|
|
508 |
$lang_code_to_name->{$short} = $raw_struct->{'localeDisplayNames'}{'languages'}{'language'}{$lng}{'content'};
|
|
509 |
$lang_name_to_code->{ Locales::normalize_for_key_lookup( $raw_struct->{'localeDisplayNames'}{'languages'}{'language'}{$lng}{'content'} ) } = $short;
|
|
510 |
}
|
|
511 |
|
|
512 |
if ($fallback_lang_code_to_name) {
|
|
513 |
for my $fb_lng ( keys %{$fallback_lang_code_to_name} ) {
|
|
514 |
if ( !exists $lang_code_to_name->{$fb_lng} ) {
|
|
515 |
$lang_code_to_name->{$fb_lng} = $fallback_lang_code_to_name->{$fb_lng};
|
|
516 |
$lang_name_to_code->{ Locales::normalize_for_key_lookup( $fallback_lang_code_to_name->{$fb_lng} ) } = $fb_lng;
|
|
517 |
}
|
|
518 |
}
|
|
519 |
}
|
|
520 |
#### /Languages ####
|
|
521 |
|
|
522 |
# TOOD: ? merge in ant $raw_struct->{'fallback'} (sans language part of $tag or 'en' since those happen alreay) locale's ?
|
|
523 |
|
|
524 |
return ( $lang_code_to_name, $lang_name_to_code, $lang_misc_info, $terr_code_to_name, $terr_name_to_code );
|
|
525 |
}
|
|
526 |
|
|
527 |
sub write_language_module {
|
|
528 |
my ( $tag, $code_to_name, $name_to_code, $misc_info ) = @_;
|
|
529 |
|
|
530 |
# init 'category_rules_compiled' key
|
|
531 |
Locales::plural_rule_hashref_to_code( $misc_info->{'plural_forms'} );
|
|
532 |
|
|
533 |
my $code_to_name_str = _stringify_hash($code_to_name);
|
|
534 |
my $name_to_code_str = _stringify_hash($name_to_code);
|
|
535 |
my $misc_info_str;
|
|
536 |
{
|
|
537 |
|
|
538 |
# make values in plural_forms->category_rules_compiled be sub { ...} instead of 'sub \{ \.\.\. \}'
|
|
539 |
#
|
|
540 |
# this adds a package thing, maybe investigate?
|
|
541 |
# local $Data::Dumper::Deparse = 1;
|
|
542 |
# for my $k (keys %{$misc_info->{plural_forms}{category_rules_compiled}}) {
|
|
543 |
# print "RULE $k: $misc_info->{plural_forms}{category_rules_compiled}{$k}\n";
|
|
544 |
# $misc_info->{plural_forms}{category_rules_compiled}{$k} = eval "$misc_info->{plural_forms}{category_rules_compiled}{$k}";
|
|
545 |
# }
|
|
546 |
|
|
547 |
$misc_info_str = _stringify_hash($misc_info);
|
|
548 |
|
|
549 |
for my $k ( keys %{ $misc_info->{'plural_forms'}{category_rules_compiled} } ) {
|
|
550 |
$misc_info_str =~ s/(\'\Q$k\E\' \=\>) \"(sub\\ \\\{.*)\"/"$1" . String::Unquotemeta::unquotemeta("$2")/e;
|
|
551 |
}
|
|
552 |
|
|
553 |
# print "DEBUG:\n$misc_info_str\n";exit;
|
|
554 |
}
|
|
555 |
_write_utf8_perl(
|
|
556 |
"Language/$tag.pm", qq{package Locales::DB::Language::$tag;
|
|
557 |
|
|
558 |
use strict;
|
|
559 |
use warnings;
|
|
560 |
|
|
561 |
# Auto generated from CLDR
|
|
562 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
563 |
|
|
564 |
\$Locales::DB::Language::$tag\::VERSION = '$mod_version';
|
|
565 |
|
|
566 |
\$Locales::DB::Language::$tag\::cldr_version = '$cldr_version';
|
|
567 |
|
|
568 |
\%Locales::DB::Language::$tag\::misc_info = (
|
|
569 |
$misc_info_str,
|
|
570 |
);
|
|
571 |
|
|
572 |
\%Locales::DB::Language::$tag\::code_to_name = (
|
|
573 |
$code_to_name_str,
|
|
574 |
);
|
|
575 |
|
|
576 |
\%Locales::DB::Language::$tag\::name_to_code = (
|
|
577 |
$name_to_code_str,
|
|
578 |
);
|
|
579 |
|
|
580 |
1;
|
|
581 |
},
|
|
582 |
);
|
|
583 |
}
|
|
584 |
|
|
585 |
sub write_territory_module {
|
|
586 |
my ( $tag, $code_to_name, $name_to_code ) = @_;
|
|
587 |
|
|
588 |
my $code_to_name_str = _stringify_hash($code_to_name);
|
|
589 |
my $name_to_code_str = _stringify_hash($name_to_code);
|
|
590 |
|
|
591 |
_write_utf8_perl(
|
|
592 |
"Territory/$tag.pm", qq{package Locales::DB::Territory::$tag;
|
|
593 |
|
|
594 |
use strict;
|
|
595 |
use warnings;
|
|
596 |
|
|
597 |
# Auto generated from CLDR
|
|
598 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
599 |
|
|
600 |
\$Locales::DB::Territory::$tag\::VERSION = '$mod_version';
|
|
601 |
|
|
602 |
\$Locales::DB::Territory::$tag\::cldr_version = '$cldr_version';
|
|
603 |
|
|
604 |
\%Locales::DB::Territory::$tag\::code_to_name = (
|
|
605 |
$code_to_name_str,
|
|
606 |
);
|
|
607 |
|
|
608 |
\%Locales::DB::Territory::$tag\::name_to_code = (
|
|
609 |
$name_to_code_str,
|
|
610 |
);
|
|
611 |
|
|
612 |
1;
|
|
613 |
|
|
614 |
},
|
|
615 |
);
|
|
616 |
|
|
617 |
}
|
|
618 |
|
|
619 |
my @_get_fast_norm_test_data = ( '', 0 );
|
|
620 |
|
|
621 |
sub _get_fast_norm_test_data {
|
|
622 |
if ( $_get_fast_norm_test_data[1] == 0 ) {
|
|
623 |
my $loc = Locales->new();
|
|
624 |
my $cnt = 12;
|
|
625 |
for my $l ( sort $loc->get_language_codes() ) {
|
|
626 |
$_get_fast_norm_test_data[0] .= qq{is(\$self_obj->get_locale_display_pattern_from_code('$l'), \$self_obj->get_locale_display_pattern_from_code_fast('$l'), 'get_locale_display_pattern_from_code[_fast] same result for $l');\n};
|
|
627 |
$_get_fast_norm_test_data[1]++;
|
|
628 |
|
|
629 |
$_get_fast_norm_test_data[0] .= qq{is(\$self_obj->get_character_orientation_from_code('$l'), \$self_obj->get_character_orientation_from_code('$l'), 'get_character_orientation_from_code[_fast] same result for $l');\n};
|
|
630 |
$_get_fast_norm_test_data[1]++;
|
|
631 |
|
|
632 |
$_get_fast_norm_test_data[0] .= "\n";
|
|
633 |
}
|
|
634 |
}
|
|
635 |
|
|
636 |
return @_get_fast_norm_test_data;
|
|
637 |
}
|
|
638 |
|
|
639 |
sub write_locale_test {
|
|
640 |
my ($tag) = @_;
|
|
641 |
|
|
642 |
my ( $fast_norm_str, $fast_norm_cnt ) = _get_fast_norm_test_data();
|
|
643 |
|
|
644 |
_write_utf8_perl(
|
|
645 |
"../../../t/042.$tag.t", qq{
|
|
646 |
# Auto generated during CLDR build
|
|
647 |
|
|
648 |
use Test::More tests => 13 + $fast_norm_cnt;
|
|
649 |
|
|
650 |
use lib 'lib', '../lib';
|
|
651 |
|
|
652 |
BEGIN {
|
|
653 |
use_ok( 'Locales::DB::Language::$tag' );
|
|
654 |
use_ok( 'Locales::DB::Territory::$tag' );
|
|
655 |
}
|
|
656 |
|
|
657 |
diag( "Sanity checking Locales::DB::Language::$tag \$Locales::DB::Language::$tag\::VERSION DB" );
|
|
658 |
|
|
659 |
use Locales;
|
|
660 |
use Locales::DB::Language::en;
|
|
661 |
use Locales::DB::Territory::en;
|
|
662 |
|
|
663 |
my \@en_lang_codes = sort(keys \%Locales::DB::Language::en::code_to_name);
|
|
664 |
my \@en_terr_codes = sort(keys \%Locales::DB::Territory::en::code_to_name);
|
|
665 |
|
|
666 |
my \@my_lang_codes = sort(keys \%Locales::DB::Language::$tag\::code_to_name);
|
|
667 |
my \@my_terr_codes = sort(keys \%Locales::DB::Territory::$tag\::code_to_name);
|
|
668 |
my \%lang_lu;
|
|
669 |
my \%terr_lu;
|
|
670 |
\@lang_lu{ \@my_lang_codes } = ();
|
|
671 |
\@terr_lu{ \@my_terr_codes } = ();
|
|
672 |
ok(\$Locales::DB::Language::$tag\::cldr_version eq \$Locales::cldr_version, 'CLDR version is correct');
|
|
673 |
ok(\$Locales::DB::Language::$tag\::VERSION eq (\$Locales::VERSION - $v_offset), 'VERSION is correct');
|
|
674 |
|
|
675 |
ok(!(grep {!exists \$lang_lu{\$_} } \@en_lang_codes), '$tag languages contains en');
|
|
676 |
ok(!(grep {!exists \$terr_lu{\$_} } \@en_terr_codes), '$tag territories contains en');
|
|
677 |
|
|
678 |
my \%uniq = ();
|
|
679 |
grep { not \$uniq{\$_}++ } \@{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_list'} };
|
|
680 |
is_deeply(
|
|
681 |
[ sort \@{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_list'} }],
|
|
682 |
[ sort keys \%uniq ],
|
|
683 |
"'category_list' contains no duplicates"
|
|
684 |
);
|
|
685 |
|
|
686 |
ok(grep(m/^other\$/, \@{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_list'} }), "'category_list' has 'other'");
|
|
687 |
|
|
688 |
is_deeply(
|
|
689 |
[ grep !m/^other\$/, sort \@{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_list'} }],
|
|
690 |
[ grep !m/^other\$/, sort keys \%{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules'} } ],
|
|
691 |
"'category_rules' has necessary 'category_list' items"
|
|
692 |
);
|
|
693 |
|
|
694 |
is_deeply(
|
|
695 |
[ sort keys \%{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules'} } ],
|
|
696 |
[ sort keys \%{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules_compiled'} } ],
|
|
697 |
"each 'category_rules' has a 'category_rules_compiled'"
|
|
698 |
);
|
|
699 |
my \$ok_rule_count = 0;
|
|
700 |
my \$error = '';
|
|
701 |
for my \$rule (keys \%{\$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules_compiled'}}) {
|
|
702 |
if (ref(\$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules_compiled'}{\$rule}) eq 'CODE') {
|
|
703 |
\$ok_rule_count++;
|
|
704 |
next;
|
|
705 |
}
|
|
706 |
eval \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules_compiled'}{\$rule};
|
|
707 |
if (\$@) {
|
|
708 |
\$error .= \$@;
|
|
709 |
next;
|
|
710 |
}
|
|
711 |
else {
|
|
712 |
\$ok_rule_count++;
|
|
713 |
}
|
|
714 |
}
|
|
715 |
ok(\$ok_rule_count == keys \%{ \$Locales::DB::Language::$tag\::misc_info{'plural_forms'}->{'category_rules_compiled'} }, "each 'category_rules_compiled' eval without error - count");
|
|
716 |
is(\$error, '', "each 'category_rules_compiled' is a code ref or evals without error - errors");
|
|
717 |
|
|
718 |
my \$self_obj = Locales->new('$tag');
|
|
719 |
ok(ref(\$self_obj), '$tag object created OK');
|
|
720 |
|
|
721 |
$fast_norm_str
|
|
722 |
|
|
723 |
},
|
|
724 |
"t/042.$tag.t",
|
|
725 |
);
|
|
726 |
}
|
|
727 |
|
|
728 |
sub write_get_plural_form_test {
|
|
729 |
my ($tag) = @_;
|
|
730 |
|
|
731 |
my $loc = Locales->new($tag) || die die "Could not create object for $tag: \$@";
|
|
732 |
|
|
733 |
my $arg_tests_count = 2;
|
|
734 |
if ( $loc->get_plural_form(0) eq 'other' ) {
|
|
735 |
$arg_tests_count = 4;
|
|
736 |
}
|
|
737 |
|
|
738 |
_write_utf8_perl(
|
|
739 |
"../../../t/06.$tag.t", qq{
|
|
740 |
# Auto generated during CLDR build
|
|
741 |
|
|
742 |
use lib 'lib', '../lib';
|
|
743 |
use Test::More;
|
|
744 |
|
|
745 |
use Locales;
|
|
746 |
|
|
747 |
diag( "Verifying perl and js get_plural_form() behave the same for $tag." );
|
|
748 |
|
|
749 |
if (!\$ENV{'RELEASE_TESTING'}) {
|
|
750 |
plan 'skip_all' => 'These tests are only run under RELEASE_TESTING.';
|
|
751 |
}
|
|
752 |
|
|
753 |
my \$obj = Locales->new('$tag') || die "Could not create object for $tag: \$@";
|
|
754 |
|
|
755 |
my \@nums = ( 0, 1.6, 2.2, 3.14159, 42.78, 0 .. 256 );
|
|
756 |
|
|
757 |
eval 'use JE ()';
|
|
758 |
plan \$@ ? ( 'skip_all' => 'JE.pm required for testing JS/Perl plural behavior tests' ) : ( 'tests' => ( scalar(\@nums) * (4 + $arg_tests_count) ) );
|
|
759 |
my \$js = JE->new();
|
|
760 |
|
|
761 |
use File::Slurp;
|
|
762 |
my \$root = '.'; # TODO: make me portable
|
|
763 |
if ( -d '../share/' ) {
|
|
764 |
\$root = '..';
|
|
765 |
}
|
|
766 |
if ( !-d "\$root/share/" ) {
|
|
767 |
die "Can not determine share directory.";
|
|
768 |
}
|
|
769 |
|
|
770 |
my \@cats = map { "args_\$_" } \$obj->get_plural_form_categories();
|
|
771 |
my \$cats_args = join(', ', map { "'\$_'" } \@cats);
|
|
772 |
|
|
773 |
my \$jsfile = File::Slurp::read_file("\$root/share/functions/\$obj->{'locale'}.js") or die "Could not read '\$root/share/functions/\$obj->{'locale'}.js': \$!";
|
|
774 |
|
|
775 |
for my \$n (\@nums) {
|
|
776 |
my \$res = \$js->eval("var X = \$jsfile;return X.get_plural_form(\$n)");
|
|
777 |
is_deeply(
|
|
778 |
[ \$res->[0], \$res->[1] ], # have to do this to stringify JE object properly
|
|
779 |
[ \$obj->get_plural_form(\$n) ],
|
|
780 |
"perl and js get_plural_form() behave the same. Tag: \$obj->{'locale'} Number: \$n"
|
|
781 |
);
|
|
782 |
is(\$res->[1], 0, "using special is 0 for \$n (no args)");
|
|
783 |
|
|
784 |
my \$res_n = \$js->eval("var X = \$jsfile;return X.get_plural_form(-\$n)");
|
|
785 |
is_deeply(
|
|
786 |
[ \$res_n->[0], \$res_n->[1] ], # have to do this to stringify JE object properly
|
|
787 |
[ \$obj->get_plural_form("-\$n") ],
|
|
788 |
"perl and js get_plural_form() behave the same. Tag: \$obj->{'locale'} Number: -\$n"
|
|
789 |
);
|
|
790 |
is(\$res_n->[1], 0, "using special is 0 for -\$n (no args)");
|
|
791 |
|
|
792 |
my \$res_s = \$js->eval("var X = \$jsfile;return X.get_plural_form(\$n,\$cats_args)");
|
|
793 |
is_deeply(
|
|
794 |
[ \$res_s->[0], \$res_s->[1] ], # have to do this to stringify JE object properly
|
|
795 |
[ \$obj->get_plural_form(\$n,\@cats) ],
|
|
796 |
"perl and js get_plural_form() behave the same. Tag: \$obj->{'locale'} Number: \$n"
|
|
797 |
);
|
|
798 |
is(\$res_s->[1], 0, "using special is 0 for \$n (args w/ no spec zero)");
|
|
799 |
|
|
800 |
if ($arg_tests_count == 4) {
|
|
801 |
my \$res_n = \$js->eval("var X = \$jsfile;return X.get_plural_form(\$n, \$cats_args, 'spec_zeroth')");
|
|
802 |
is_deeply(
|
|
803 |
[ \$res_n->[0], \$res_n->[1] ], # have to do this to stringify JE object properly
|
|
804 |
[ \$obj->get_plural_form("\$n",\@cats, 'spec_zeroth') ],
|
|
805 |
"perl and js get_plural_form() behave the same. Tag: \$obj->{'locale'} Number: \$n"
|
|
806 |
);
|
|
807 |
my \$spec_bool = \$n == 0 ? 1 : 0;
|
|
808 |
is(\$res_n->[1], \$spec_bool, "using special is \$spec_bool for \$n (args w/ spec zero)");
|
|
809 |
}
|
|
810 |
|
|
811 |
# TODO: ? too many/too few args and check for carp ?
|
|
812 |
}
|
|
813 |
},
|
|
814 |
"t/06.$tag.t",
|
|
815 |
);
|
|
816 |
}
|
|
817 |
|
|
818 |
sub write_native_module {
|
|
819 |
my ( $native_map, $fallback_lookup ) = @_;
|
|
820 |
|
|
821 |
my $code_to_name_str = _stringify_hash_no_dumper($native_map);
|
|
822 |
my $fallback_lookup_str = _stringify_hash_no_dumper($fallback_lookup);
|
|
823 |
|
|
824 |
# nerd alert! TODO: verify during next build
|
|
825 |
if ( $code_to_name_str->{'tlh'} eq 'Klingon' ) { # i.e. no CLDR data for tlh
|
|
826 |
|
|
827 |
# "\x{f8e4}\x{f8d7}\x{f8dc}\x{f8d0}\x{f8db}"
|
|
828 |
# "\xef\xa3\xa4\xef\xa3\x97\xef\xa3\x9c\xef\xa3\x90\xef\xa3\x9b"
|
|
829 |
$code_to_name_str->{'tlh'} = ""; # need a font to see this, like Bengali
|
|
830 |
}
|
|
831 |
|
|
832 |
_write_utf8_perl(
|
|
833 |
"$locales_db/Native.pm", qq{package Locales::DB::Native;
|
|
834 |
|
|
835 |
use strict;
|
|
836 |
use warnings;
|
|
837 |
|
|
838 |
# Auto generated from CLDR
|
|
839 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
840 |
|
|
841 |
\$Locales::DB::Native::VERSION = '$mod_version';
|
|
842 |
|
|
843 |
\$Locales::DB::Native::cldr_version = '$cldr_version';
|
|
844 |
|
|
845 |
\%Locales::DB::Native::code_to_name = (
|
|
846 |
$code_to_name_str);
|
|
847 |
|
|
848 |
\%Locales::DB::Native::value_is_fallback = (
|
|
849 |
$fallback_lookup_str);
|
|
850 |
|
|
851 |
1;
|
|
852 |
},
|
|
853 |
'lib/Locales/DB/Native.pm',
|
|
854 |
1,
|
|
855 |
);
|
|
856 |
}
|
|
857 |
|
|
858 |
sub write_db_loadable_module {
|
|
859 |
my $en = Locales->new('en');
|
|
860 |
|
|
861 |
my $code_hr;
|
|
862 |
my $terr_hr;
|
|
863 |
|
|
864 |
for my $t ( $en->get_territory_codes() ) {
|
|
865 |
$terr_hr->{$t} = 1;
|
|
866 |
}
|
|
867 |
|
|
868 |
for my $c ( $en->get_language_codes() ) {
|
|
869 |
next if Locales::is_non_locale($c);
|
|
870 |
|
|
871 |
if ( Locales->new($c) ) {
|
|
872 |
$code_hr->{$c} = 1;
|
|
873 |
}
|
|
874 |
}
|
|
875 |
|
|
876 |
my $code_str = _stringify_hash_no_dumper($code_hr);
|
|
877 |
my $terr_str = _stringify_hash_no_dumper($terr_hr);
|
|
878 |
|
|
879 |
_write_utf8_perl(
|
|
880 |
"$locales_db/Loadable.pm", qq{package Locales::DB::Loadable;
|
|
881 |
|
|
882 |
use strict;
|
|
883 |
use warnings;
|
|
884 |
|
|
885 |
# Auto generated from CLDR
|
|
886 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
887 |
|
|
888 |
\$Locales::DB::Loadable::VERSION = '$mod_version';
|
|
889 |
|
|
890 |
\$Locales::DB::Loadable::cldr_version = '$cldr_version';
|
|
891 |
|
|
892 |
\%Locales::DB::Loadable::code = (
|
|
893 |
$code_str);
|
|
894 |
|
|
895 |
\%Locales::DB::Loadable::territory = (
|
|
896 |
$terr_str);
|
|
897 |
|
|
898 |
1;
|
|
899 |
},
|
|
900 |
'lib/Locales/DB/Loadable.pm',
|
|
901 |
1,
|
|
902 |
);
|
|
903 |
|
|
904 |
}
|
|
905 |
|
|
906 |
sub write_character_orientation_module {
|
|
907 |
my ( $text_direction_map, $fallback_lookup ) = @_;
|
|
908 |
|
|
909 |
my $code_to_name_str = _stringify_hash_no_dumper($text_direction_map);
|
|
910 |
my $fallback_lookup_str = _stringify_hash_no_dumper($fallback_lookup);
|
|
911 |
|
|
912 |
_write_utf8_perl(
|
|
913 |
"$locales_db/CharacterOrientation.pm", qq{package Locales::DB::CharacterOrientation;
|
|
914 |
|
|
915 |
use strict;
|
|
916 |
use warnings;
|
|
917 |
|
|
918 |
# Auto generated from CLDR
|
|
919 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
920 |
|
|
921 |
\$Locales::DB::CharacterOrientation::VERSION = '$mod_version';
|
|
922 |
|
|
923 |
\$Locales::DB::CharacterOrientation::cldr_version = '$cldr_version';
|
|
924 |
|
|
925 |
\%Locales::DB::CharacterOrientation::code_to_name = (
|
|
926 |
$code_to_name_str);
|
|
927 |
|
|
928 |
\%Locales::DB::CharacterOrientation::value_is_fallback = (
|
|
929 |
$fallback_lookup_str);
|
|
930 |
|
|
931 |
1;
|
|
932 |
},
|
|
933 |
'lib/Locales/DB/CharacterOrientation.pm',
|
|
934 |
1,
|
|
935 |
);
|
|
936 |
|
|
937 |
File::Path::Tiny::mk("$locales_db/CharacterOrientation") || die "Could not create '$locales_db/CharacterOrientation': $!";
|
|
938 |
my $rtl;
|
|
939 |
for my $name ( keys %{$text_direction_map} ) {
|
|
940 |
if ( $text_direction_map->{$name} eq 'right-to-left' ) {
|
|
941 |
$rtl->{$name} = undef();
|
|
942 |
}
|
|
943 |
elsif ( $text_direction_map->{$name} ne 'left-to-right' ) {
|
|
944 |
warn "$name is neither right-to-left or left-to-right";
|
|
945 |
}
|
|
946 |
}
|
|
947 |
die "Locales::DB::CharacterOrientation::Tiny lookup hash not built" if ref($rtl) ne 'HASH';
|
|
948 |
$rtl = _stringify_hash_no_dumper($rtl);
|
|
949 |
|
|
950 |
_write_utf8_perl(
|
|
951 |
"$locales_db/CharacterOrientation/Tiny.pm", qq{package Locales::DB::CharacterOrientation::Tiny;
|
|
952 |
|
|
953 |
use strict;
|
|
954 |
use warnings;
|
|
955 |
|
|
956 |
# Auto generated from CLDR
|
|
957 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
958 |
|
|
959 |
\$Locales::DB::CharacterOrientation::Tiny::VERSION = '$mod_version';
|
|
960 |
|
|
961 |
\$Locales::DB::CharacterOrientation::Tiny::cldr_version = '$cldr_version';
|
|
962 |
|
|
963 |
my \%rtl = (
|
|
964 |
$rtl);
|
|
965 |
|
|
966 |
sub get_orientation {
|
|
967 |
if ( exists \$rtl{ \$_[0] } ) {
|
|
968 |
return 'right-to-left';
|
|
969 |
}
|
|
970 |
else {
|
|
971 |
require Locales;
|
|
972 |
my (\$l) = Locales::split_tag(\$_[0]);
|
|
973 |
if (\$l ne \$_[0]) {
|
|
974 |
return 'right-to-left' if exists \$rtl{ \$l };
|
|
975 |
}
|
|
976 |
return 'left-to-right';
|
|
977 |
}
|
|
978 |
}
|
|
979 |
|
|
980 |
1;
|
|
981 |
},
|
|
982 |
'lib/Locales/DB/CharacterOrientation/Tiny.pm',
|
|
983 |
1,
|
|
984 |
);
|
|
985 |
}
|
|
986 |
|
|
987 |
sub write_name_pattern_module {
|
|
988 |
my ( $name_pattern, $isfallback ) = @_;
|
|
989 |
|
|
990 |
my $name_pattern_str = _stringify_hash_no_dumper($name_pattern);
|
|
991 |
my $fallback_lookup_str = _stringify_hash_no_dumper($isfallback);
|
|
992 |
|
|
993 |
_write_utf8_perl(
|
|
994 |
"$locales_db/LocaleDisplayPattern.pm", qq{package Locales::DB::LocaleDisplayPattern;
|
|
995 |
|
|
996 |
use strict;
|
|
997 |
use warnings;
|
|
998 |
|
|
999 |
# Auto generated from CLDR
|
|
1000 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
1001 |
|
|
1002 |
\$Locales::DB::LocaleDisplayPattern::VERSION = '$mod_version';
|
|
1003 |
|
|
1004 |
\$Locales::DB::LocaleDisplayPattern::cldr_version = '$cldr_version';
|
|
1005 |
|
|
1006 |
\%Locales::DB::LocaleDisplayPattern::code_to_pattern = (
|
|
1007 |
$name_pattern_str);
|
|
1008 |
|
|
1009 |
\%Locales::DB::LocaleDisplayPattern::value_is_fallback = (
|
|
1010 |
$fallback_lookup_str);
|
|
1011 |
|
|
1012 |
1;
|
|
1013 |
},
|
|
1014 |
'lib/Locales/DB/LocaleDisplayPattern.pm',
|
|
1015 |
1,
|
|
1016 |
);
|
|
1017 |
|
|
1018 |
# $locales_db/LocaleDisplayPattern
|
|
1019 |
File::Path::Tiny::mk("$locales_db/LocaleDisplayPattern") || die "Could not create '$locales_db/CharacterOrientation': $!";
|
|
1020 |
|
|
1021 |
my $name_pattern_hr;
|
|
1022 |
|
|
1023 |
require Locales::DB::Language::en;
|
|
1024 |
my $default_pattern = $Locales::DB::Language::en::misc_info{'cldr_formats'}{'locale'};
|
|
1025 |
for my $k ( keys %{$name_pattern} ) {
|
|
1026 |
next if !$name_pattern->{$k} || $name_pattern->{$k} =~ m/^\s+$/ || $name_pattern->{$k} eq $default_pattern;
|
|
1027 |
$name_pattern_hr->{$k} = $name_pattern->{$k};
|
|
1028 |
}
|
|
1029 |
|
|
1030 |
die "Locales::DB::LocaleDisplayPattern::Tiny lookup hash not built" if ref($name_pattern_hr) ne 'HASH';
|
|
1031 |
$name_pattern_hr = _stringify_hash_no_dumper($name_pattern_hr);
|
|
1032 |
|
|
1033 |
$default_pattern = quotemeta($default_pattern);
|
|
1034 |
|
|
1035 |
# $locales_db/LocaleDisplayPattern/Tiny.pm
|
|
1036 |
_write_utf8_perl(
|
|
1037 |
"$locales_db/LocaleDisplayPattern/Tiny.pm", qq{package Locales::DB::LocaleDisplayPattern::Tiny;
|
|
1038 |
|
|
1039 |
use strict;
|
|
1040 |
use warnings;
|
|
1041 |
|
|
1042 |
# Auto generated from CLDR
|
|
1043 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
1044 |
|
|
1045 |
\$Locales::DB::LocaleDisplayPattern::Tiny::VERSION = '$mod_version';
|
|
1046 |
|
|
1047 |
\$Locales::DB::LocaleDisplayPattern::Tiny::cldr_version = '$cldr_version';
|
|
1048 |
|
|
1049 |
my \%locale_display_lookup = (
|
|
1050 |
$name_pattern_hr);
|
|
1051 |
|
|
1052 |
sub get_locale_display_pattern {
|
|
1053 |
if ( exists \$locale_display_lookup{ \$_[0] } ) {
|
|
1054 |
return \$locale_display_lookup{ \$_[0] };
|
|
1055 |
}
|
|
1056 |
else {
|
|
1057 |
require Locales;
|
|
1058 |
my (\$l) = Locales::split_tag(\$_[0]);
|
|
1059 |
if (\$l ne \$_[0]) {
|
|
1060 |
return \$locale_display_lookup{\$l} if exists \$locale_display_lookup{ \$l };
|
|
1061 |
}
|
|
1062 |
return "$default_pattern";
|
|
1063 |
}
|
|
1064 |
}
|
|
1065 |
|
|
1066 |
1;
|
|
1067 |
},
|
|
1068 |
'lib/Locales/DB/LocaleDisplayPattern/Tiny.pm',
|
|
1069 |
1,
|
|
1070 |
);
|
|
1071 |
}
|
|
1072 |
|
|
1073 |
sub write_plural_forms_argument_pod {
|
|
1074 |
my ( $plural_forms, $isfallback ) = @_;
|
|
1075 |
File::Path::Tiny::mk("$locales_db/Docs") || die "Could not create '$locales_db/Docs': $!";
|
|
1076 |
|
|
1077 |
my $pod_starts = '__END__'; # this is to help prevent mis-parsing for CPAN like rt 76129 (probably not necessary)
|
|
1078 |
my $pkg = 'Locales::DB::Docs::PluralForms'; # this is to help prevent mis-parsing for CPAN like rt 76129
|
|
1079 |
my $pod_mark = '='; # this is to help prevent mis-parsing for CPAN like rt 80546 (and not fixed *again* in 0.28)
|
|
1080 |
my $pod_items = '';
|
|
1081 |
|
|
1082 |
for my $ent ( @{$plural_forms} ) {
|
|
1083 |
|
|
1084 |
if ( exists $isfallback->{ $ent->{'tag'} } ) {
|
|
1085 |
$pod_items .= "=item $ent->{'tag'}\n\nCLDR $cldr_version did not define data for “$ent->{'tag'}”, thus it will fallback to L</en> behavior.\n\nYou can L<submit the missing data to the CLDR|http://unicode.org/cldr/trac> if you wish.\n\n";
|
|
1086 |
}
|
|
1087 |
else {
|
|
1088 |
$pod_items .= "=item $ent->{'tag'}\n\n$fb get_plural_form(\$n, $ent->{'csv'})\n";
|
|
1089 |
if ( $ent->{'zero_is_not_other'} ) {
|
|
1090 |
$pod_items .= "\nNote: zero falls under a different category than “other” so there is no L</“Special Zero” Argument> for $ent->{'tag'}\n\n";
|
|
1091 |
}
|
|
1092 |
else {
|
|
1093 |
$pod_items .= " get_plural_form(\$n, $ent->{'csv'}, special_zero)\n\n";
|
|
1094 |
}
|
|
1095 |
}
|
|
1096 |
}
|
|
1097 |
|
|
1098 |
# $locales_db/Docs/PluralForms.pm
|
|
1099 |
_write_utf8_perl(
|
|
1100 |
"$locales_db/Docs/PluralForms.pm", qq{package $pkg;
|
|
1101 |
|
|
1102 |
use strict;
|
|
1103 |
use warnings;
|
|
1104 |
|
|
1105 |
# Auto generated from CLDR
|
|
1106 |
use if \$Locales::_UNICODE_STRINGS, 'utf8';
|
|
1107 |
|
|
1108 |
\$Locales::DB::Docs::PluralForms::VERSION = '$mod_version';
|
|
1109 |
|
|
1110 |
\$Locales::DB::Docs::PluralForms::cldr_version = '$cldr_version';
|
|
1111 |
|
|
1112 |
1;
|
|
1113 |
|
|
1114 |
$pod_starts
|
|
1115 |
|
|
1116 |
${pod_mark}encoding utf-8
|
|
1117 |
|
|
1118 |
${pod_mark}head1 NAME
|
|
1119 |
|
|
1120 |
Locales::DB::Docs::PluralForms - plural form details reference for all
|
|
1121 |
included locales
|
|
1122 |
|
|
1123 |
${pod_mark}head1 VERSION
|
|
1124 |
|
|
1125 |
Locales.pm v$mod_version (based on CLDR v$cldr_version)
|
|
1126 |
|
|
1127 |
${pod_mark}head1 DESCRIPTION
|
|
1128 |
|
|
1129 |
CLDR L<defines a set of broad plural categories and rules|http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html> that determine which category any given number will fall under.
|
|
1130 |
|
|
1131 |
L<Locales> allows you to determine the plural categories applicable to a specific locale and also which category a given number will fall under in that locale.
|
|
1132 |
|
|
1133 |
This POD documents which categories and in what order you'd specify them in additional arguments to L<Locales/get_plural_form()> (i.e. the optional arguments after the number).
|
|
1134 |
|
|
1135 |
${pod_mark}head2 “Special Zero” Argument
|
|
1136 |
|
|
1137 |
In addition to the CLDR category value list you can also specify one additional argument of what to use for zero instead of the value for “other”.
|
|
1138 |
|
|
1139 |
This won't be used if 0 falls under a specific category besides “other”.
|
|
1140 |
|
|
1141 |
${pod_mark}head1 Plural Category Argument Order Reference
|
|
1142 |
|
|
1143 |
${pod_mark}over 4
|
|
1144 |
|
|
1145 |
$pod_items
|
|
1146 |
|
|
1147 |
${pod_mark}back
|
|
1148 |
|
|
1149 |
${pod_mark}head1 BUGS AND LIMITATIONS
|
|
1150 |
|
|
1151 |
Please see L<Locales/BUGS AND LIMITATIONS>
|
|
1152 |
|
|
1153 |
${pod_mark}head2 BEFORE YOU SUBMIT A BUG REPORT
|
|
1154 |
|
|
1155 |
Please see L<Locales/BEFORE YOU SUBMIT A BUG REPORT>
|
|
1156 |
|
|
1157 |
${pod_mark}head1 AUTHOR
|
|
1158 |
|
|
1159 |
Daniel Muey C<< <http://drmuey.com/cpan_contact.pl> >>
|
|
1160 |
|
|
1161 |
${pod_mark}head1 LICENCE AND COPYRIGHT
|
|
1162 |
|
|
1163 |
Copyright (c) 2009, Daniel Muey C<< <http://drmuey.com/cpan_contact.pl> >>. All rights reserved.
|
|
1164 |
|
|
1165 |
This module is free software; you can redistribute it and/or
|
|
1166 |
modify it under the same terms as Perl itself. See L<perlartistic>.
|
|
1167 |
|
|
1168 |
${pod_mark}head1 DISCLAIMER OF WARRANTY
|
|
1169 |
|
|
1170 |
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
1171 |
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
1172 |
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
1173 |
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
1174 |
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
1175 |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
|
1176 |
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
|
|
1177 |
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
|
|
1178 |
NECESSARY SERVICING, REPAIR, OR CORRECTION.
|
|
1179 |
|
|
1180 |
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
1181 |
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
1182 |
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
|
|
1183 |
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
|
|
1184 |
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
|
|
1185 |
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
1186 |
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
1187 |
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
1188 |
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
1189 |
SUCH DAMAGES.
|
|
1190 |
|
|
1191 |
},
|
|
1192 |
'lib/Locales/DB/Docs/PluralForms.pm',
|
|
1193 |
1,
|
|
1194 |
);
|
|
1195 |
}
|
|
1196 |
|
|
1197 |
sub build_javascript_share {
|
|
1198 |
my ($tag) = @_;
|
|
1199 |
|
|
1200 |
if ( -d 'share/' ) {
|
|
1201 |
File::Path::Tiny::rm('share/') || die "Could not remove 'share/': $!";
|
|
1202 |
}
|
|
1203 |
for my $d (qw(misc_info/ functions/ code_to_name/ datetime/ db/)) {
|
|
1204 |
File::Path::Tiny::mk("share/$d") || die "Could not create 'share/$d': $!";
|
|
1205 |
}
|
|
1206 |
|
|
1207 |
my $loc = Locales->new();
|
|
1208 |
for my $tag ( sort $loc->get_language_codes() ) {
|
|
1209 |
my $tag_loc = Locales->new($tag) || next;
|
|
1210 |
|
|
1211 |
my $guts_m = $tag_loc->{'language_data'}{'misc_info'};
|
|
1212 |
for my $k ( keys %{ $guts_m->{'plural_forms'}{'category_rules_compiled'} } ) {
|
|
1213 |
$guts_m->{'plural_forms'}{'category_rules_compiled'}{$k} = Locales::plural_rule_string_to_javascript_code( $guts_m->{'plural_forms'}{'category_rules'}{$k}, $k );
|
|
1214 |
}
|
|
1215 |
my $json = JSON::Syck::Dump($guts_m); # no eval, lets just die
|
|
1216 |
$json =~ s/\"(function \(n\) \{)/$1/g;
|
|
1217 |
$json =~ s/(return\;\})\"/$1/g;
|
|
1218 |
|
|
1219 |
open( my $fh_m, '>', "share/misc_info/$tag.js" ) or die "Could not open 'share/misc_info/$tag.js': $!";
|
|
1220 |
print {$fh_m} $json;
|
|
1221 |
close $fh_m;
|
|
1222 |
|
|
1223 |
my $cats_list_js = JSON::Syck::Dump( $guts_m->{'plural_forms'}{'category_list'} );
|
|
1224 |
my $cats_proc_js = JSON::Syck::Dump( [ Locales::get_cldr_plural_category_list(1) ] );
|
|
1225 |
my $cats_rule_js = JSON::Syck::Dump( $guts_m->{'plural_forms'}{'category_rules_compiled'} );
|
|
1226 |
$cats_rule_js =~ s/"(function[^"]+)"/$1/g;
|
|
1227 |
|
|
1228 |
open( my $fh_f, '>', "share/functions/$tag.js" ) or die "Could not open 'share/functions/$tag.js': $!";
|
|
1229 |
|
|
1230 |
# var category_process_order = $cats_proc_js;
|
|
1231 |
# var category_rules_lookup = $cats_rule_js;
|
|
1232 |
# var categories = $cats_list_js;
|
|
1233 |
|
|
1234 |
my $js_code = <<"END_FUNC";
|
|
1235 |
{
|
|
1236 |
'get_plural_form' : function (n) {
|
|
1237 |
var category;
|
|
1238 |
var category_values = Array.prototype.slice.call(arguments,1);
|
|
1239 |
|
|
1240 |
var has_extra_for_zero = 0;
|
|
1241 |
var abs_n = Math.abs(n);
|
|
1242 |
var category_process_order = $cats_proc_js;
|
|
1243 |
var category_rules_lookup = $cats_rule_js;
|
|
1244 |
|
|
1245 |
for (i=0; i < category_process_order.length; i++) {
|
|
1246 |
if (category_rules_lookup[category_process_order[i]]) {
|
|
1247 |
category = category_rules_lookup[category_process_order[i]](abs_n);
|
|
1248 |
if (category) break;
|
|
1249 |
}
|
|
1250 |
}
|
|
1251 |
|
|
1252 |
var categories = $cats_list_js;
|
|
1253 |
|
|
1254 |
if ( category_values.length === 0 ) {
|
|
1255 |
category_values = categories; // no args will return the category name
|
|
1256 |
}
|
|
1257 |
else {
|
|
1258 |
var cat_len = categories.length;
|
|
1259 |
var val_len = category_values.length;
|
|
1260 |
|
|
1261 |
var cat_len_plus_one = cat_len + 1;
|
|
1262 |
if ( val_len === cat_len_plus_one ) {
|
|
1263 |
has_extra_for_zero++;
|
|
1264 |
}
|
|
1265 |
else if ( cat_len !== val_len ) {
|
|
1266 |
if (window.console) console.warn( 'The number of given values (' + val_len + ') does not match the number of categories (' + cat_len + ').' );
|
|
1267 |
}
|
|
1268 |
}
|
|
1269 |
|
|
1270 |
if ( category === undefined) {
|
|
1271 |
var cat_idx = has_extra_for_zero && abs_n !== 0 ? -2 : -1;
|
|
1272 |
var sliced = category_values.slice(cat_idx);
|
|
1273 |
return [sliced[0], has_extra_for_zero && abs_n === 0 ? 1 : 0];
|
|
1274 |
}
|
|
1275 |
else {
|
|
1276 |
var return_value;
|
|
1277 |
GET_POSITION:
|
|
1278 |
while(1) {
|
|
1279 |
var cat_pos_in_list;
|
|
1280 |
var index = -1;
|
|
1281 |
CATEGORY:
|
|
1282 |
for (i=0; i < categories.length; i++ ) {
|
|
1283 |
index++;
|
|
1284 |
if ( categories[i] === category ) {
|
|
1285 |
cat_pos_in_list = index;
|
|
1286 |
break CATEGORY;
|
|
1287 |
}
|
|
1288 |
}
|
|
1289 |
|
|
1290 |
if ( cat_pos_in_list === undefined && category !== 'other' ) {
|
|
1291 |
if (window.console) console.warn( 'The category (' + category + ') is not used by this locale.');
|
|
1292 |
category = 'other';
|
|
1293 |
continue GET_POSITION;
|
|
1294 |
}
|
|
1295 |
else if ( cat_pos_in_list === undefined) {
|
|
1296 |
var cat_idx = has_extra_for_zero && abs_n !== 0 ? -2 : -1;
|
|
1297 |
var sliced = category_values.slice(cat_idx);
|
|
1298 |
return_value = [sliced[0], has_extra_for_zero && abs_n === 0 ? 1 : 0]
|
|
1299 |
break GET_POSITION;
|
|
1300 |
}
|
|
1301 |
else {
|
|
1302 |
if ( has_extra_for_zero && category === 'other' ) {
|
|
1303 |
var cat_idx = has_extra_for_zero && abs_n === 0 ? -1 : cat_pos_in_list;
|
|
1304 |
var sliced = category_values.slice(cat_idx);
|
|
1305 |
return_value = [sliced[0], has_extra_for_zero && abs_n === 0 ? 1 : 0];
|
|
1306 |
break GET_POSITION;
|
|
1307 |
}
|
|
1308 |
else {
|
|
1309 |
return_value = [category_values[cat_pos_in_list], 0];
|
|
1310 |
break GET_POSITION;
|
|
1311 |
}
|
|
1312 |
}
|
|
1313 |
break GET_POSITION;
|
|
1314 |
}
|
|
1315 |
|
|
1316 |
return return_value;
|
|
1317 |
}
|
|
1318 |
}
|
|
1319 |
}
|
|
1320 |
END_FUNC
|
|
1321 |
print {$fh_f} JavaScript::Minifier::XS::minify($js_code);
|
|
1322 |
close $fh_f;
|
|
1323 |
|
|
1324 |
my $json_c = JSON::Syck::Dump( $tag_loc->{'language_data'}{'code_to_name'} ); # no eval, lets just die
|
|
1325 |
|
|
1326 |
open( my $fh_c, '>', "share/code_to_name/$tag.json" ) or die "Could not open 'share/code_to_name/$tag.json': $!";
|
|
1327 |
print {$fh_c} $json_c;
|
|
1328 |
close $fh_c;
|
|
1329 |
|
|
1330 |
my $dt_struct;
|
|
1331 |
my $dt_loc = eval { DateTime::Locale->load( Locales::normalize_tag_for_datetime_locale($tag) ) };
|
|
1332 |
if ($@) {
|
|
1333 |
|
|
1334 |
# Locales has $tag but DateTime::Locales does not (different CLDR version probably)
|
|
1335 |
print "$tag datetime JSON will be en: $@";
|
|
1336 |
$dt_loc = DateTime::Locale->load('en');
|
|
1337 |
}
|
|
1338 |
|
|
1339 |
for my $format (@dt_available_formats) {
|
|
1340 |
$dt_struct->{'format_for'}{$format} = $dt_loc->format_for($format); # no eval, should die since it means incomplete data
|
|
1341 |
}
|
|
1342 |
for my $meth (@dt_methods) {
|
|
1343 |
my $res = $dt_loc->$meth();
|
|
1344 |
$dt_struct->{$meth} =
|
|
1345 |
ref($res) eq 'ARRAY' ? [ @{$res} ]
|
|
1346 |
: ref($res) eq 'HASH' ? { %{$res} }
|
|
1347 |
: $res;
|
|
1348 |
}
|
|
1349 |
|
|
1350 |
my $json_d = JSON::Syck::Dump($dt_struct); # no eval, lets just die
|
|
1351 |
open( my $fh_d, '>', "share/datetime/$tag.json" ) or die "Could not open 'share/datetime/$tag.json': $!";
|
|
1352 |
print {$fh_d} $json_d;
|
|
1353 |
close $fh_d;
|
|
1354 |
|
|
1355 |
append_file( $manifest, "share/misc_info/$tag.js\nshare/code_to_name/$tag.json\nshare/datetime/$tag.json\nshare/functions/$tag.js\n" );
|
|
1356 |
}
|
|
1357 |
|
|
1358 |
require Locales::DB::Loadable;
|
|
1359 |
my $json_d = JSON::Syck::Dump( { 'code' => \%Locales::DB::Loadable::code, 'territory' => \%Locales::DB::Loadable::territory } ); # no eval, lets just die
|
|
1360 |
open( my $fh_d, '>', "share/db/loadable.json" ) or die "Could not open 'share/db/loadable.json': $!";
|
|
1361 |
print {$fh_d} $json_d;
|
|
1362 |
close $fh_d;
|
|
1363 |
|
|
1364 |
append_file( $manifest, "share/db/loadable.json" );
|
|
1365 |
}
|
|
1366 |
|
|
1367 |
sub build_manifest {
|
|
1368 |
my $base = $manifest;
|
|
1369 |
$base =~ s{\.build$}{};
|
|
1370 |
my @in = read_file("$base.in");
|
|
1371 |
my @bl = read_file("$base.build");
|
|
1372 |
write_file( $base, @in, @bl );
|
|
1373 |
}
|
|
1374 |
|
|
1375 |
sub do_changelog {
|
|
1376 |
my $changelog = $manifest;
|
|
1377 |
$changelog =~ s{MANIFEST\.build$}{Changes};
|
|
1378 |
my @cl = read_file($changelog);
|
|
1379 |
return if grep /^$Locales::VERSION\s+/, @cl;
|
|
1380 |
|
|
1381 |
my $time = localtime();
|
|
1382 |
my $new_ent = <<"END_CL";
|
|
1383 |
$Locales::VERSION $time
|
|
1384 |
- Updated data to CLDR $Locales::cldr_version
|
|
1385 |
|
|
1386 |
END_CL
|
|
1387 |
write_file( $changelog, $new_ent, @cl );
|
|
1388 |
}
|
|
1389 |
|
|
1390 |
sub _write_utf8_perl {
|
|
1391 |
my ( $file, $guts, $mani, $open_plain ) = @_;
|
|
1392 |
|
|
1393 |
my $open = $open_plain ? '>' : '>:utf8'; #:utf8 breaks Native.pm
|
|
1394 |
|
|
1395 |
open( my $fh, $open, $file ) or die "Could not open '$file': $!";
|
|
1396 |
print {$fh} $guts;
|
|
1397 |
close $fh;
|
|
1398 |
|
|
1399 |
system( qw(perltidy -b), $file ) == 0 || die "perltidy failed, '$file' probably has syntax errors";
|
|
1400 |
unlink "$file.bak";
|
|
1401 |
|
|
1402 |
append_file( $manifest, $mani ? "$mani\n" : "lib/Locales/DB/$file\n" );
|
|
1403 |
}
|
|
1404 |
|
|
1405 |
sub _stringify_hash_no_dumper {
|
|
1406 |
my $string;
|
|
1407 |
for my $k ( keys %{ $_[0] } ) {
|
|
1408 |
my $qk = $k;
|
|
1409 |
my $qv = $_[0]->{$k};
|
|
1410 |
$qk =~ s{\'}{\\\'}g;
|
|
1411 |
$qv =~ s{\'}{\\\'}g;
|
|
1412 |
my $ky = $k ne $qk ? qq{"$qk"} : qq{'$k'};
|
|
1413 |
my $vl = $_[0]->{$k} ne $qv ? qq{"$qv"} : qq{'$_[0]->{$k}'};
|
|
1414 |
$string .= "$ky => $vl,\n";
|
|
1415 |
}
|
|
1416 |
return $string;
|
|
1417 |
}
|
|
1418 |
|
|
1419 |
sub _stringify_hash {
|
|
1420 |
my $string = Dumper( $_[0] );
|
|
1421 |
$string =~ s/^\s*\{\s*//;
|
|
1422 |
$string =~ s/\s*\}\s*$//;
|
|
1423 |
return $string;
|
|
1424 |
}
|
|
1425 |
|
|
1426 |
1;
|