File Coverage

blib/lib/Locale/Country/Multilingual.pm
Criterion Covered Total %
statement 111 119 93.2
branch 28 42 66.6
condition 26 35 74.2
subroutine 23 24 95.8
pod 7 7 100.0
total 195 227 85.9


line stmt bran cond sub pod time code
1             package Locale::Country::Multilingual;
2             $Locale::Country::Multilingual::VERSION = '0.25';
3 6     6   205088 use strict;
  6         18  
  6         247  
4 6     6   37 use warnings;
  6         12  
  6         188  
5              
6 6     6   35 use base 'Class::Data::Inheritable';
  6         24  
  6         6245  
7              
8 6     6   3524 use 5.008;
  6         22  
  6         238  
9              
10 6     6   6694 use Symbol;
  6         6738  
  6         546  
11 6     6   54 use File::Spec;
  6         14  
  6         135  
12 6     6   36 use Carp;
  6         11  
  6         937  
13              
14             __PACKAGE__->mk_classdata(dir => (__FILE__ =~ /(.+)\.pm/)[0]);
15             __PACKAGE__->mk_classdata(languages => {});
16             __PACKAGE__->mk_classdata('use_io_layer');
17              
18 6     6   40 use constant CODE => 0;
  6         11  
  6         499  
19 6     6   35 use constant COUNTRY => 1;
  6         14  
  6         263  
20 6     6   76 use constant LOCALE_CODE_ALPHA_2 => 0;
  6         13  
  6         253  
21 6     6   30 use constant LOCALE_CODE_ALPHA_3 => 1;
  6         12  
  6         255  
22 6     6   33 use constant LOCALE_CODE_NUMERIC => 2;
  6         11  
  6         313  
23 6         10647 use constant MAP_LOCALE_CODE_STR_TO_IDX => {
24             LOCALE_CODE_ALPHA_2 => 0,
25             LOCALE_CODE_ALPHA_3 => 1,
26             LOCALE_CODE_NUMERIC => 2,
27 6     6   36 };
  6         12  
28              
29              
30             croak __PACKAGE__->dir, ": $!"
31             unless -d __PACKAGE__->dir;
32              
33             sub import {
34 6     6   51 my $class = shift;
35              
36 6 100       7208 return unless @_;
37              
38 2 100       10 my $opts = ref($_[-1]) eq 'HASH' ? pop : {};
39              
40 2         11 $class->use_io_layer($opts->{use_io_layer});
41              
42 2         1636 $class->_load_data($_) for @_;
43             }
44              
45             sub new {
46 8     8 1 5785 my $class = shift;
47 8         18 my %args;
48              
49 8 100       66 %args = @_ if @_;
50 8         79 return bless {
51             use_io_layer => 0,
52             %args,
53             }, $class;
54             }
55              
56             sub set_lang {
57 3     3 1 2451 my $self = shift;
58              
59 3 50       22 $self->{'lang'} = shift if @_;
60             }
61              
62             sub assert_lang {
63 0     0 1 0 my $self = shift;
64              
65 0         0 foreach (@_) {
66 0 0       0 eval { $self->_load_data($_) }
  0         0  
67             and return $_;
68             }
69 0         0 return undef;
70             }
71              
72              
73             sub code2country {
74 9     9 1 3809 my $self = shift;
75 9 50       37 my $code = shift
76             or return;
77              
78 9 50       39 return if $code =~ /\W/;
79              
80 9   100     91 my $lang = shift || $self->{lang} || 'en';
81 9         63 my $language = $self->_load_data($lang);
82              
83 9 100       77 if ($code =~ /^\d+$/) {
    100          
    50          
84 1         8 return $language->[CODE]->[LOCALE_CODE_NUMERIC]->{$code + 0};
85             } elsif (length($code) == 2) {
86 7         72 return $language->[CODE]->[LOCALE_CODE_ALPHA_2]->{uc($code)};
87             } elsif (length($code) == 3) {
88 1         6 return $language->[CODE]->[LOCALE_CODE_ALPHA_3]->{uc($code)};
89             }
90 0         0 return;
91             }
92              
93             sub country2code {
94 5     5 1 2942 my ($self, $country, $codeset, $lang) = @_;
95              
96 5 50       20 return undef unless defined $country;
97 5         12 $country = lc($country);
98              
99 5   50     38 $lang ||= $self->{lang} || 'en';
      66        
100 5         13 my $language = $self->_load_data($lang);
101              
102 5   100     71 return $language->[COUNTRY]
      100        
103             ->[MAP_LOCALE_CODE_STR_TO_IDX->{$codeset || 'LOCALE_CODE_ALPHA_2'} || 0]
104             ->{$country};
105             }
106              
107             sub all_country_codes {
108 6     6 1 1044 my ($self, $codeset) = @_;
109              
110 6   100     75 my $lang ||= $self->{lang} || 'en';
      33        
111 6         23 my $language = $self->_load_data($lang);
112              
113             return keys %{
114 6   100     13 $language->[CODE]
  6   100     819  
115             ->[MAP_LOCALE_CODE_STR_TO_IDX->{$codeset || 'LOCALE_CODE_ALPHA_2'} || 0]
116             };
117             }
118              
119             sub all_country_names {
120 2     2 1 1279 my ($self, $lang) = @_;
121              
122 2   50     17 $lang ||= $self->{lang} || 'en';
      66        
123 2         6 my $language = $self->_load_data($lang);
124              
125 2         6 return values %{ $language->[CODE]->[LOCALE_CODE_ALPHA_2] };
  2         921  
126             }
127              
128             sub _load_data {
129 26     26   55 my $self = shift;
130 26         65 my $lang = lc shift;
131              
132 26         147 my $languages = $self->languages;
133 26         350 my $language = $languages->{$lang};
134              
135 26 100       144 return $language if ref $language; # already set
136              
137 16         67 ($lang, my $fh) = $self->_open_dat($lang);
138 16 100 66     94 binmode $fh, ':utf8'
      66        
139             if $self->use_io_layer or ref($self) and $self->{use_io_layer};
140              
141 16         315 $language = $languages->{$lang} = [[], []];
142              
143 16         1108 my $codes = $language->[CODE];
144 16         33 my $countries = $language->[COUNTRY];
145 16         18820 while (my $line = <$fh>) {
146 3978         7625 chomp $line;
147 3978         27612 my ($alpha2, $alpha3, $numeric, @countries) = split(/:/, $line);
148 3978 50       12749 next unless ($alpha2);
149 3978         13445 $codes->[LOCALE_CODE_ALPHA_2]->{$alpha2} = $countries[0];
150 3978 50       18655 $codes->[LOCALE_CODE_ALPHA_3]->{$alpha3} = $countries[0] if ($alpha3);
151 3978 50       19985 $codes->[LOCALE_CODE_NUMERIC]->{$numeric + 0} = $countries[0] if ($numeric);
152 3978         8838 foreach my $country (@countries) {
153 4141     1   25893 $countries->[LOCALE_CODE_ALPHA_2]->{"\L$country"} = $alpha2;
  1         11  
  1         1  
  1         19  
154 4141 50       66404 $countries->[LOCALE_CODE_ALPHA_3]->{"\L$country"} = $alpha3 if ($alpha3);
155 4141 50       45918 $countries->[LOCALE_CODE_NUMERIC]->{"\L$country"} = $numeric if ($numeric);
156             }
157             }
158 16         365 close $fh; # be a nice kid
159              
160 16         1851 return $language;
161             }
162              
163             sub _open_dat {
164 16     16   35 my $self = shift;
165 16   50     60 my $filename = shift || '';
166 16         583 my $fh = gensym; # required before Perl 5.6
167 16         1529 my @errors;
168             my $lang; # stores the actual name used for loading
169              
170             # backwards compatibility
171 16 100       99 if ($filename eq 'cn') {
    50          
172 1         2 $filename = 'zh'; # zh is simplified Han Chinese (hans)
173             }
174             elsif ($filename eq 'tw') {
175 0         0 $filename = 'zh-tw'; # zh-tw is traditional Han Chinese (hant)
176             }
177              
178             # be tolerant on language identifier format as long as language comes
179             # first, optionally followed by region:
180             # "en_GB", "en-gb", "EN -> GB" is all the same.
181 16         139 for (my @lang = split /[^A-Za-z]+/, $filename; @lang; pop @lang) {
182 18         51 $lang = join('-', @lang);
183 18         80 $filename = File::Spec->catfile($self->dir, "$lang.dat");
184 18 50 100     2564 open $fh, $filename
185             and return $lang => $fh
186             or push @errors, "$filename: $!";
187             }
188             # succeed or die
189 0         0 croak join(', ', @errors);
190             }
191              
192             1;
193              
194             =pod
195              
196             =encoding utf-8
197              
198             =head1 NAME
199              
200             Locale::Country::Multilingual - Map ISO codes to localized country names
201              
202             =head1 VERSION
203              
204             version 0.25
205              
206             =head1 SYNOPSIS
207              
208             use Locale::Country::Multilingual {use_io_layer => 1};
209              
210             my $lcm = Locale::Country::Multilingual->new();
211             my $country = $lcm->code2country('JP'); # $country gets 'Japan'
212             $country = $lcm->code2country('CHN'); # $country gets 'China'
213             $country = $lcm->code2country('250'); # $country gets 'France'
214             my $code = $lcm->country2code('Norway'); # $code gets 'NO'
215              
216             $lcm->set_lang('zh'); # set default language to Chinese
217             $country = $lcm->code2country('CN'); # $country gets '中国'
218             $code = $lcm->country2code('日本'); # $code gets 'JP'
219              
220             my @codes = $lcm->all_country_codes();
221             my @names = $lcm->all_country_names();
222              
223             # more heavy call
224             my $lang = 'en';
225             $country = $lcm->code2country('CN', $lang); # $country gets 'China'
226             $lang = 'zh';
227             $country = $lcm->code2country('CN', $lang); # $country gets '中国'
228              
229             my $CODE = 'LOCALE_CODE_ALPHA_2'; # by default
230             $code = $lcm->country2code('Norway', $CODE); # $code gets 'NO'
231             $CODE = 'LOCALE_CODE_ALPHA_3';
232             $code = $lcm->country2code('Norway', $CODE); # $code gets 'NOR'
233             $CODE = 'LOCALE_CODE_NUMERIC';
234             $code = $lcm->country2code('Norway', $CODE); # $code gets '578'
235             $code = $lcm->country2code('挪威', $CODE, 'zh'); # with lang=zh
236              
237             $CODE = 'LOCALE_CODE_ALPHA_3';
238             $lang = 'zh';
239             @codes = $lcm->all_country_codes($CODE); # return codes with 3alpha
240             @names = $lcm->all_country_names($lang); # get all Chinese Countries Names
241              
242             =head1 DESCRIPTION
243              
244             C is an OO replacement for
245             L, and supports country names in several
246             languages.
247              
248             =head2 Language Codes
249              
250             A language is selected by a two-letter language code as described by
251             ISO 639-1 L.
252             This code can be amended by a two-letter region code, that is described by
253             ISO 3166-1 L.
254             This combination of language and region is also described in RFC 4646
255             L and RFC 4647
256             L, and is commonly used for
257             HTTP 1.1 L and the POSIX
258             L function. Codes can be given in small or capital letters
259             and be divided by an arbitrary string of none-letter ASCII bytes (but
260             C<"-"> or C<"_"> is recommended).
261              
262             =head2 Language Selection Fallback
263              
264             In case a language code contains a region, language selection falls back to
265             the two-letter language code if no specific language file for the region
266             exists. Example: For C<"zh_CN"> selection will fall back to C<"zh"> since
267             there is no file F<"zh-cn.dat"> - actually C<"zh.dat"> happens to contain
268             the country names in Simplified (Han) Chinese.
269              
270             =head1 INCOMPATIBILITY NOTICE
271              
272             =head2 ISO Compliance
273              
274             C defines I codes in upper case letters. C
275             defines I codes in lower case letters. This facilitates
276             differentiation between language and country codes.
277              
278             Beginning with release version 0.20 method L returns country
279             codes in capital letters. On the input side all methods accept country and
280             language codes in any case for maximum convenience.
281              
282             This document uses upper case letters for country codes and lower case
283             letters for language codes.
284              
285             =head2 Unicode Support
286              
287             Unicode implementation before release 0.07 was broken. In fact it still is
288             for the benefit of downwards compatibility, but can be fixed by using the
289             C option. If you use this module without C,
290             then your code is broken.
291              
292             Beginning with release 0.30 C will be enabled by default.
293              
294             Beginning with release 0.40 C will be removed.
295              
296             =head2 Deprecated Languages
297              
298             Releases before 0.09 of this module offered languages C<"cn"> and C<"tw">.
299             Those were replaced by C<"zh"> and C<"zh-tw"> to comply with the ISO 639
300             standard and RFC 2616. C<"cn"> and C<"tw"> are still supported, but will be
301             removed in a near future - probably in release 0.30.
302              
303             =head1 METHODS
304              
305             =head2 import
306              
307             use Locale::Country::Multilingual 'en', 'fr', {use_io_layer => 1};
308              
309             The C class method is called when a module is C'd.
310             Language files can be pre-loaded at compile time, by specifying their
311             language codes. This can be useful when several processes are forked
312             from the main application, e.g. in an Apache C environment -
313             language data that is loaded before forking is shared by all processes and
314             thus saving memory.
315              
316             The last argument can be a reference to a hash of options.
317              
318             The only option ATM is C and works for Perl 5.8 and higher. See
319             L
320             for more information.
321              
322             =head2 new
323              
324             $lcm = Locale::Country::Multilingual->new;
325             $lcm = Locale::Country::Multilingual->new(
326             lang => 'es',
327             use_io_layer => 1,
328             );
329              
330             Constructor method. Accepts optional list of named arguments:
331              
332             =over 4
333              
334             =item lang
335              
336             The language to use. See L for what codes are
337             accepted.
338              
339             =item use_io_layer
340              
341             Set this C if you need correct encoding behavior. See
342             L
343             for more information.
344              
345             =back
346              
347             =head2 set_lang
348              
349             $lcm->set_lang('de');
350              
351             Set the current language. Only argument is a language code as described in
352             the L above.
353              
354             See L for what codes are accepted.
355              
356             This method does not actually load the language data. Use L
357             if you really need to know for sure if a language is supported.
358              
359             =head2 assert_lang
360              
361             $lang = $lcm->assert_lang('es', 'it', 'fr');
362              
363             Tries to load any of the given languages. Returns the language code for
364             the first language that was successfully loaded. Returns C if none
365             of the given languages could be loaded. Actually loads the language data,
366             but does not L, so you probably want to use it
367             this way:
368              
369             $lang = $lcm->assert_lang(qw/es it fr en/)
370             and $lcm->set_lang($lang)
371             or die "unable to load any language\n";
372              
373             =head2 code2country
374              
375             $country = $lcm->code2country('GB');
376             $country = $lcm->code2country('GB', 'zh');
377              
378             Turns an ISO 3166-1 code into a country name in the current language.
379             The default language is C<"en">.
380              
381             Accepts either two-letter or a three-letter code or a 3 digit numerical code.
382              
383             A language might be given as second argument to set the output language only
384             for this call - it does not change the current language, that was set with
385             L.
386              
387             Returns the country name.
388              
389             This method L if the language is not available.
390              
391             =head2 country2code
392              
393             $code = $lcm->country2code(
394             'République tchèque', 'LOCALE_CODE_ALPHA_2', 'fr'
395             );
396              
397             Take a country name and return the two-letter code when available.
398             Aside from being case-insensitive the country must be written exactly the
399             way how L returns it.
400              
401             The second argument is optional and can be one of C<"LOCALE_CODE_ALPHA_2">,
402             C<"LOCALE_CODE_ALPHA_3"> and C<"LOCALE_CODE_NUMERIC">. The default is
403             C<"LOCALE_CODE_ALPHA2">.
404              
405             The third argument is the language to use for the country name and is
406             optional too.
407              
408             Returns an ISO-3166 code or C if search fails.
409              
410             This method L if the language is not available.
411              
412             =head2 all_country_codes
413              
414             @countrycodes = $lcm->all_country_codes;
415             @countrycodes = $lcm->all_country_codes($codeset);
416              
417             Returns an unsorted list of all ISO-3166 codes.
418              
419             The argument is optional and can be one of C<"LOCALE_CODE_ALPHA_2">,
420             C<"LOCALE_CODE_ALPHA_3"> and C<"LOCALE_CODE_NUMERIC">. The default is
421             C<"LOCALE_CODE_ALPHA2">.
422              
423             =head2 all_country_names
424              
425             @countrynames = $lcm->all_country_names;
426             @countrynames = $lcm->all_country_names('fr');
427              
428             Returns an unsorted list of country names in the current or given locale.
429              
430             =head1 AVAILABLE LANGAUGES
431              
432             =over 4
433              
434             =item en English
435              
436             =item bg Bulgarian
437              
438             =item bn Bengali
439              
440             =item ca Catalan
441              
442             =item cs Czech
443              
444             =item cy Welsh
445              
446             =item da Danish
447              
448             =item de German
449              
450             =item dz Dzongkha
451              
452             =item el Greek
453              
454             =item eo Esperanto
455              
456             =item es Spanish
457              
458             =item et Estonian
459              
460             =item eu Basque
461              
462             =item fa Persian
463              
464             =item fi Finnish
465              
466             =item fo Faroese
467              
468             =item fr French
469              
470             =item ga Irish
471              
472             =item gl Galician
473              
474             =item gu Gujarati
475              
476             =item he Hebrew
477              
478             =item hi Hindi
479              
480             =item hr Croatian
481              
482             =item hu Hungarian
483              
484             =item hy Armenian
485              
486             =item id Indonesian
487              
488             =item ii Sichuan Yi
489              
490             =item is Icelandic
491              
492             =item it Italian
493              
494             =item ja Japanese
495              
496             =item ka Georgian
497              
498             =item km Central Khmer
499              
500             =item kn Kannada
501              
502             =item ko Korean
503              
504             =item ln Lingala
505              
506             =item lo Lao
507              
508             =item lt Lithuanian
509              
510             =item lv Latvian
511              
512             =item mk Macedonian
513              
514             =item ml Malayalam
515              
516             =item mn Mongolian
517              
518             =item ms Malay
519              
520             =item mt Maltese
521              
522             =item my Burmese
523              
524             =item nb Norwegian Bokmål
525              
526             =item ne Nepali
527              
528             =item nl Dutch
529              
530             =item nn Norwegian Nynorsk
531              
532             =item no Norwegian
533              
534             =item pl Polish
535              
536             =item ps Pushto
537              
538             =item pt Portuguese
539              
540             =item ro Romanian
541              
542             =item ru Russian
543              
544             =item se Northern Sami
545              
546             =item sk Slovak
547              
548             =item sl Slovenian
549              
550             =item so Somali
551              
552             =item sq Albanian
553              
554             =item sr Serbian
555              
556             =item sv Swedish
557              
558             =item sw Swahili
559              
560             =item ta Tamil
561              
562             =item te Telugu
563              
564             =item th Thai
565              
566             =item to Tonga
567              
568             =item tr Turkish
569              
570             =item uk Ukrainian
571              
572             =item ur Urdu
573              
574             =item uz Uzbek
575              
576             =item vi Vietnamese
577              
578             =item zh (zh-cn) Chinese Simp.
579              
580             =item zh-tw Chinese Trad.
581              
582             =back
583              
584             Language files are more or less (in-)complete and fall back to English.
585             Corrections, additions and more languages are highly appreciated.
586              
587             =head1 SUPPORTS
588              
589             =over 4
590              
591             =item GitHub
592              
593             L
594              
595             =back
596              
597             =head1 SEE ALSO
598              
599             L,
600             ISO 639 L,
601             ISO 3166 L,
602             RFC 2616 L
603             RFC 4646 L,
604             RFC 4647 L,
605             Unicode CLDR Project L
606              
607             =head1 ACKNOWLEDGEMENTS
608              
609             Thanks to michele ongaro for Italian/Spanish/Portuguese/German/French/Japanese dat files.
610              
611             Thanks to Andreas Marienborg for Norwegian dat file.
612              
613             Thanks to all contributors of the Unicode CLDR Project.
614              
615             =head1 CLDR LICENSE
616              
617             Part of the data used for this module is generated from data provided by
618             the CLDR project. See the LICENSE.cldr in this distribution for details
619             on the CLDR data's license.
620              
621             =head1 AUTHORS
622              
623             =over 4
624              
625             =item *
626              
627             Bernhard Graf
628              
629             =item *
630              
631             Fayland Lam
632              
633             =item *
634              
635             Greg Oschwald
636              
637             =back
638              
639             =head1 COPYRIGHT AND LICENSE
640              
641             This software is copyright (c) 2014 by Fayland Lam.
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             =cut
647              
648             __END__