File Coverage

blib/lib/Locale/CLDR.pm
Criterion Covered Total %
statement 1199 1545 77.6
branch 289 544 53.1
condition 116 259 44.7
subroutine 173 202 85.6
pod 55 57 96.4
total 1832 2607 70.2


line stmt bran cond sub pod time code
1              
2             =encoding utf8
3              
4             =head1 NAME
5              
6             Locale::CLDR - A Module to create locale objects with localisation data from the CLDR
7              
8             =head1 VERSION
9              
10             Version 0.34.1
11              
12             =head1 SYNOPSIS
13              
14             This module provides a locale object you can use to localise your output.
15             The localisation data comes from the Unicode Common Locale Data Repository.
16             Most of this code can be used with Perl version 5.10.1 or above. There are a
17             few parts of the code that require version 5.18 or above.
18              
19             =head1 USAGE
20              
21             my $locale = Locale::CLDR->new('en_US');
22              
23             or
24              
25             my $locale = Locale::CLDR->new(language_id => 'en', region_id => 'us');
26            
27             A full locale identifier is
28            
29             C<language>_C<script>_C<region>_C<variant>_u_C<extension name>_C<extension value>
30            
31             my $locale = Locale::CLDR->new('en_latn_US_SCOUSE_u_nu_traditional');
32            
33             or
34            
35             my $locale = Locale::CLDR->new(language_id => 'en', script_id => 'latn', region_id => 'US', variant => 'SCOUSE', extensions => { nu => 'traditional' } );
36            
37             =cut
38              
39             use v5.10.1;
40 21     21   1729059 use version;
  21         222  
41 21     21   6710 our $VERSION = version->declare('v0.34.1');
  21         30477  
  21         111  
42              
43             use open ':encoding(utf8)';
44 21     21   9441 use utf8;
  21         18416  
  21         95  
45 21     21   195961 use if $^V ge v5.12.0, feature => 'unicode_strings';
  21         51  
  21         113  
46 21     21   1049 use if $^V le v5.16, charnames => 'full';
  21         46  
  21         864  
47 21     21   2271  
  21         37  
  21         151  
48             use Moo;
49 21     21   8911 use MooX::ClassAttribute;
  21         182204  
  21         90  
50 21     21   31380 use Types::Standard qw( Str Int Maybe ArrayRef HashRef Object Bool InstanceOf );
  21         315227  
  21         107  
51 21     21   12324  
  21         1138501  
  21         237  
52             with 'Locale::CLDR::ValidCodes', 'Locale::CLDR::EraBoundries', 'Locale::CLDR::WeekData',
53             'Locale::CLDR::MeasurementSystem', 'Locale::CLDR::LikelySubtags', 'Locale::CLDR::NumberingSystems',
54             'Locale::CLDR::NumberFormatter', 'Locale::CLDR::RegionContainment', 'Locale::CLDR::CalendarPreferences',
55             'Locale::CLDR::Currencies', 'Locale::CLDR::Plurals';
56            
57             use Class::Load;
58 21     21   36218 use namespace::autoclean;
  21         271958  
  21         849  
59 21     21   7637 use List::Util qw(first);
  21         127799  
  21         73  
60 21     21   1398 use DateTime::Locale;
  21         36  
  21         1062  
61 21     21   8666 use Unicode::Normalize();
  21         3052531  
  21         677  
62 21     21   10476 use Locale::CLDR::Collator();
  21         35316  
  21         559  
63 21     21   7922 use File::Spec();
  21         75  
  21         519  
64 21     21   140 use Scalar::Util qw(blessed);
  21         35  
  21         368  
65 21     21   95 use Unicode::Regex::Set();
  21         54  
  21         904  
66 21     21   8972  
  21         27274  
  21         2241  
67             # Backwards compatibility
68             BEGIN {
69             if (defined &CORE::fc) { #v5.16
70 21 50   21   104 *fc = \&CORE::fc;
71 21         22971 }
72             else {
73             # We only use fc() with code that expects Perl v5.18 or above
74             *fc = sub {};
75 0         0 }
76             }
77              
78             =head1 ATTRIBUTES
79              
80             These can be passed into the constructor and all are optional.
81              
82             =over 4
83              
84             =item language_id
85              
86             A valid language or language alias id, such as C<en>
87              
88             =cut
89              
90             has 'language_id' => (
91             is => 'ro',
92             isa => Str,
93             required => 1,
94             );
95              
96             # language aliases
97             around 'language_id' => sub {
98             my ($orig, $self) = @_;
99             my $value = $self->$orig;
100             return $self->language_aliases->{$value} // $value;
101             };
102              
103             =item script_id
104              
105             A valid script id, such as C<latn> or C<Ctcl>. The code will pick a likely script
106             depending on the given language if non is provided.
107              
108             =cut
109              
110             has 'script_id' => (
111             is => 'ro',
112             isa => Str,
113             default => '',
114             predicate => 'has_script',
115             );
116              
117             =item region_id
118              
119             A valid region id or region alias such as C<GB>
120              
121             =cut
122              
123             has 'region_id' => (
124             is => 'ro',
125             isa => Str,
126             default => '',
127             predicate => 'has_region',
128             );
129              
130             # region aliases
131             around 'region_id' => sub {
132             my ($orig, $self) = @_;
133             my $value = $self->$orig;
134             my $alias = $self->region_aliases->{$value};
135             return $value if ! defined $alias;
136             return (split /\s+/, $alias)[0];
137             };
138              
139             =item variant_id
140              
141             A valid variant id. The code currently ignores this
142              
143             =cut
144              
145             has 'variant_id' => (
146             is => 'ro',
147             isa => Str,
148             default => '',
149             predicate => 'has_variant',
150             );
151              
152             =item extensions
153              
154             A Hashref of extension names and values. You can use this to override
155             the locales number formatting and calendar by passing in the Unicode
156             extension names or aliases as keys and the extension value as the hash
157             value.
158              
159             Currently supported extensions are
160              
161             =over 8
162              
163             =item ca
164              
165             =item calendar
166              
167             You can use this to override a locales default calendar. Valid values are
168              
169             =over 12
170              
171             =item buddhist
172              
173             Thai Buddhist calendar
174              
175             =item chinese
176              
177             Traditional Chinese calendar
178              
179             =item coptic
180              
181             Coptic calendar
182              
183             =item dangi
184              
185             Traditional Korean calendar
186              
187             =item ethioaa
188              
189             =item ethiopic-amete-alem
190              
191             Ethiopic calendar, Amete Alem (epoch approx. 5493 B.C.E)
192              
193             =item ethiopic
194              
195             Ethiopic calendar, Amete Mihret (epoch approx, 8 C.E.)
196              
197             =item gregory
198              
199             =item gregorian
200              
201             Gregorian calendar
202              
203             =item hebrew
204              
205             Hebrew Calendar
206              
207             =item indian
208              
209             Indian National Calendar
210              
211             =item islamic
212              
213             Islamic Calendar
214              
215             =item islamic-civil
216              
217             Islamic Calendar (tabular, civil epoch)
218              
219             =item islamic-rgsa
220              
221             Islamic Calendar (Saudi Arabia, sighting)
222              
223             =item islamic-tbla
224              
225             Islamic Calendar (tabular, astronomical epoch)
226              
227             =item islamic-umalqura
228              
229             Islamic Calendar (Umm al-Qura)
230              
231             =item iso8601
232              
233             ISO-8601 Calendar
234              
235             =item japanese
236              
237             Japanese Calendar
238              
239             =item persian
240              
241             Persian Calendar
242              
243             =item roc
244              
245             Minguo Calendar
246              
247             =back
248              
249             =item nu
250              
251             =item numbers
252              
253             The number type can be one of
254              
255             =over 12
256              
257             =item arab
258              
259             Arabic-Indic Digits
260              
261             =item arabext
262              
263             Extended Arabic-Indic Digits
264              
265             =item armn
266              
267             Armenian Numerals
268              
269             =item armnlow
270              
271             Armenian Lowercase Numerals
272              
273             =item bali
274              
275             Balinese Digits
276              
277             =item beng
278              
279             Bengali Digits
280              
281             =item brah
282              
283             Brahmi Digits
284              
285             =item cakm
286              
287             Chakma Digits
288              
289             =item cham
290              
291             Cham Digits
292              
293             =item deva
294              
295             Devanagari Digits
296              
297             =item ethi
298              
299             Ethiopic Numerals
300              
301             =item finance
302              
303             Financial Numerals
304              
305             =item fullwide
306              
307             Full Width Digits
308              
309             =item geor
310              
311             Georgian Numerals
312              
313             =item grek
314              
315             Greek Numerals
316              
317             =item greklow
318              
319             Greek Lowercase Numerals
320              
321             =item gujr
322              
323             Gujarati Digits
324              
325             =item guru
326              
327             Gurmukhi Digits
328              
329             =item hanidays
330              
331             Chinese Calendar Day-of-Month Numerals
332              
333             =item hanidec
334              
335             Chinese Decimal Numerals
336              
337             =item hans
338              
339             Simplified Chinese Numerals
340              
341             =item hansfin
342              
343             Simplified Chinese Financial Numerals
344              
345             =item hant
346              
347             Traditional Chinese Numerals
348              
349             =item hantfin
350              
351             Traditional Chinese Financial Numerals
352              
353             =item hebr
354              
355             Hebrew Numerals
356              
357             =item java
358              
359             Javanese Digits
360              
361             =item jpan
362              
363             Japanese Numerals
364              
365             =item jpanfin
366              
367             Japanese Financial Numerals
368              
369             =item kali
370              
371             Kayah Li Digits
372              
373             =item khmr
374              
375             Khmer Digits
376              
377             =item knda
378              
379             Kannada Digits
380              
381             =item lana
382              
383             Tai Tham Hora Digits
384              
385             =item lanatham
386              
387             Tai Tham Tham Digits
388              
389             =item laoo
390              
391             Lao Digits
392              
393             =item latn
394              
395             Western Digits
396              
397             =item lepc
398              
399             Lepcha Digits
400              
401             =item limb
402              
403             Limbu Digits
404              
405             =item mlym
406              
407             Malayalam Digits
408              
409             =item mong
410              
411             Mongolian Digits
412              
413             =item mtei
414              
415             Meetei Mayek Digits
416              
417             =item mymr
418              
419             Myanmar Digits
420              
421             =item mymrshan
422              
423             Myanmar Shan Digits
424              
425             =item native
426              
427             Native Digits
428              
429             =item nkoo
430              
431             N'Ko Digits
432              
433             =item olck
434              
435             Ol Chiki Digits
436              
437             =item orya
438              
439             Oriya Digits
440              
441             =item osma
442              
443             Osmanya Digits
444              
445             =item roman
446              
447             Roman Numerals
448              
449             =item romanlow
450              
451             Roman Lowercase Numerals
452              
453             =item saur
454              
455             Saurashtra Digits
456              
457             =item shrd
458              
459             Sharada Digits
460              
461             =item sora
462              
463             Sora Sompeng Digits
464              
465             =item sund
466              
467             Sundanese Digits
468              
469             =item takr
470              
471             Takri Digits
472              
473             =item talu
474              
475             New Tai Lue Digits
476              
477             =item taml
478              
479             Traditional Tamil Numerals
480              
481             =item tamldec
482              
483             Tamil Digits
484              
485             =item telu
486              
487             Telugu Digits
488              
489             =item thai
490              
491             Thai Digits
492              
493             =item tibt
494              
495             Tibetan Digits
496              
497             =item traditional
498              
499             Traditional Numerals
500              
501             =item vaii
502              
503             Vai Digits
504              
505             =back
506              
507             =item cu
508              
509             =item currency
510              
511             This extention overrides the default currency symbol for the locale.
512             It's value is any valid currency identifyer.
513              
514             =item cf
515              
516             This overrides the default currency format. It can be set to one of
517             C<standard> or C<account>
518              
519             =item fw
520              
521             This extention overrides the first day of the week. It can be set to
522             one of
523              
524             =over 12
525              
526             =item mon
527              
528             =item tue
529              
530             =item wed
531              
532             =item thu
533              
534             =item fri
535              
536             =item sat
537              
538             =item sun
539              
540             =back
541              
542             =back
543              
544             =cut
545              
546             has 'extensions' => (
547             is => 'ro',
548             isa => Maybe[HashRef],
549             default => undef,
550             writer => '_set_extensions',
551             );
552              
553             =back
554              
555             =head1 Methods
556              
557             The following methods can be called on the locale object
558              
559             =over 4
560              
561             =item id()
562              
563             The local identifier. This is what you get if you attempt to
564             stringify a locale object.
565              
566             =item has_region()
567              
568             True if a region id was passed into the constructor
569              
570             =item has_script()
571              
572             True if a script id was passed into the constructor
573              
574             =item has_variant()
575              
576             True if a variant id was passed into the constructor
577              
578             =item likely_language()
579              
580             Given a locale with no language passed in or with the explicit language
581             code of C<und>, this method attempts to use the script and region
582             data to guess the locale's language.
583              
584             =cut
585              
586             has 'likely_language' => (
587             is => 'ro',
588             isa => Str,
589             init_arg => undef,
590             lazy => 1,
591             builder => '_build_likely_language',
592             );
593              
594             my $self = shift;
595            
596 0     0   0 my $language = $self->language_id();
597            
598 0         0 return $self->language unless $language eq 'und';
599            
600 0 0       0 return $self->likely_subtag->language;
601             }
602 0         0  
603             =item likely_script()
604              
605             Given a locale with no script passed in this method attempts to use the
606             language and region data to guess the locale's script.
607              
608             =cut
609              
610             has 'likely_script' => (
611             is => 'ro',
612             isa => Str,
613             init_arg => undef,
614             lazy => 1,
615             builder => '_build_likely_script',
616             );
617              
618             my $self = shift;
619            
620             my $script = $self->script();
621 0     0   0
622             return $script if $script;
623 0         0
624             return $self->likely_subtag->script || '';
625 0 0       0 }
626              
627 0   0     0 =item likely_region()
628              
629             Given a locale with no region passed in this method attempts to use the
630             language and script data to guess the locale's region.
631              
632             =back
633              
634             =cut
635              
636             has 'likely_region' => (
637             is => 'ro',
638             isa => Str,
639             init_arg => undef,
640             lazy => 1,
641             builder => '_build_likely_region',
642             );
643              
644             my $self = shift;
645            
646             my $region = $self->region();
647            
648 0     0   0 return $region if $region;
649            
650 0         0 return $self->likely_subtag->region || '';
651             }
652 0 0       0  
653             has 'module' => (
654 0   0     0 is => 'ro',
655             isa => Object,
656             init_arg => undef,
657             lazy => 1,
658             builder => '_build_module',
659             );
660              
661             # Create the new path
662             my $self = shift;
663            
664             my @path = map { ucfirst lc }
665             map { $_ ? $_ : 'Any' } (
666             $self->language_id,
667 116     116   412 $self->script_id,
668             $self->region_id,
669 348         820 );
670 116 100       2380  
  348         839  
671             my @likely_path =
672             map { ucfirst lc } (
673             $self->_has_likely_subtag ? $self->likely_subtag->language_id : 'Any',
674             $self->_has_likely_subtag ? $self->likely_subtag->script_id : 'Any',
675             $self->_has_likely_subtag ? $self->likely_subtag->region_id : 'Any',
676             );
677 116 100       1060
  348 100       611  
    100          
678             for (my $i = 0; $i < @path; $i++) {
679             $likely_path[$i] = $path[$i] unless $path[$i] eq 'und' or $path[$i] eq 'Any';
680             }
681            
682             # Note the order we push these onto the stack is important
683 116         433 @path = join '::', @likely_path;
684 348 100 66     1401 push @path, join '::', $likely_path[0], 'Any', $likely_path[2];
685             push @path, join '::', @likely_path[0 .. 1];
686             push @path, join '::', $likely_path[0];
687            
688 116         484 # Strip out all paths that end in ::Any
689 116         388 @path = grep { ! /::Any$/ } @path;
690 116         387
691 116         245 # Now we go through the path loading each module
692             # And calling new on it.
693             my $module;
694 116         218 my $errors;
  464         1002  
695             my $module_name;
696             foreach my $name (@path) {
697             $module_name = "Locale::CLDR::Locales::$name";
698 116         352 my ($canload, $error) = Class::Load::try_load_class($module_name, { -version => $VERSION});
699             if ($canload) {
700 116         0 Class::Load::load_class($module_name, { -version => $VERSION});
701 116         308 $errors = 0;
702 231         429 last;
703 231         1241 }
704 230 100       60171 else {
705 95         660 $errors = 1;
706 95         12399 }
707 95         212 }
708              
709             if ($errors) {
710 135         312 Class::Load::load_class('Locale::CLDR::Locales::Root');
711             $module_name = 'Locale::CLDR::Locales::Root';
712             }
713            
714 115 100       405 $module = $module_name->new;
715 20         96  
716 20         1276 # If we only have the root module then we have a problem as
717             # none of the language specific data is in the root. So we
718             # fall back to the en module
719 115         2253  
720             if ( ref $module eq 'Locale::CLDR::Locales::Root') {
721             Class::Load::load_class('Locale::CLDR::Locales::En');
722             $module = Locale::CLDR::Locales::En->new
723             }
724              
725 115 100       3833 return $module;
726 20         144 }
727 20         2292  
728             class_has 'method_cache' => (
729             is => 'rw',
730 115         34350 isa => HashRef[HashRef[ArrayRef[Object]]],
731             init_arg => undef,
732             default => sub { return {}},
733             );
734              
735             has 'break_grapheme_cluster' => (
736             is => 'ro',
737             isa => ArrayRef,
738             init_arg => undef(),
739             lazy => 1,
740             default => sub {shift->_build_break('GraphemeClusterBreak')},
741             );
742              
743             has 'break_word' => (
744             is => 'ro',
745             isa => ArrayRef,
746             init_arg => undef(),
747             lazy => 1,
748             default => sub {shift->_build_break('WordBreak')},
749             );
750              
751             has 'break_line' => (
752             is => 'ro',
753             isa => ArrayRef,
754             init_arg => undef(),
755             lazy => 1,
756             default => sub {shift->_build_break('LineBreak')},
757             );
758              
759             has 'break_sentence' => (
760             is => 'ro',
761             isa => ArrayRef,
762             init_arg => undef(),
763             lazy => 1,
764             default => sub {shift->_build_break('SentenceBreak')},
765             );
766              
767             =head2 Meta Data
768              
769             The following methods return, in English, the names if the various
770             id's passed into the locales constructor. I.e. if you passed
771             C<language =E<gt> 'fr'> to the constructor you would get back C<French>
772             for the language.
773              
774             =over 4
775              
776             =item name
777              
778             The locale's name. This is usually built up out of the language,
779             script, region and variant of the locale
780              
781             =item language
782              
783             The name of the locale's language
784              
785             =item script
786              
787             The name of the locale's script
788              
789             =item region
790              
791             The name of the locale's region
792              
793             =item variant
794              
795             The name of the locale's variant
796              
797             =back
798              
799             =head2 Native Meta Data
800              
801             Like Meta Data above this provides the names of the various id's
802             passed into the locale's constructor. However in this case the
803             names are formatted to match the locale. I.e. if you passed
804             C<language =E<gt> 'fr'> to the constructor you would get back
805             C<français> for the language.
806              
807             =over 4
808              
809             =item native_name
810              
811             The locale's name. This is usually built up out of the language,
812             script, region and variant of the locale. Returned in the locale's
813             language and script
814              
815             =item native_language
816              
817             The name of the locale's language in the locale's language and script.
818              
819             =item native_script
820              
821             The name of the locale's script in the locale's language and script.
822              
823             =item native_region
824              
825             The name of the locale's region in the locale's language and script.
826              
827             =item native_variant
828              
829             The name of the locale's variant in the locale's language and script.
830              
831             =back
832              
833             =cut
834              
835             foreach my $property (qw( name language script region variant)) {
836             has $property => (
837             is => 'ro',
838             isa => Str,
839             init_arg => undef,
840             lazy => 1,
841             builder => "_build_$property",
842             );
843              
844             no strict 'refs';
845             *{"native_$property"} = sub {
846             my ($self, $for) = @_;
847            
848             $for //= $self;
849 21     21   169 my $build = "_build_native_$property";
  21         43  
  21         14386  
850             return $self->$build($for);
851 0     0   0 };
852             }
853 0   0     0  
854 0         0 =head2 Calenders
855 0         0  
856             The Calendar data is built to hook into L<DateTime::Locale> so that
857             all Locale::CLDR objects can be used as replacements for DateTime::Locale's
858             locale data. To use, say, the French data do
859              
860             my $french_locale = Locale::CLDR->new('fr_FR');
861             my $french_dt = DateTime->now(locale => $french_locale);
862             say "French month : ", $french_dt->month_name; # prints out the current month in French
863              
864             =over 4
865              
866             =item month_format_wide
867              
868             =item month_format_abbreviated
869              
870             =item month_format_narrow
871              
872             =item month_stand_alone_wide
873              
874             =item month_stand_alone_abbreviated
875              
876             =item month_stand_alone_narrow
877              
878             All the above return an arrayref of month names in the requested style.
879              
880             =item day_format_wide
881              
882             =item day_format_abbreviated
883              
884             =item day_format_narrow
885              
886             =item day_stand_alone_wide
887              
888             =item day_stand_alone_abbreviated
889              
890             =item day_stand_alone_narrow
891              
892             All the above return an array ref of day names in the requested style.
893              
894             =item quarter_format_wide
895              
896             =item quarter_format_abbreviated
897              
898             =item quarter_format_narrow
899              
900             =item quarter_stand_alone_wide
901              
902             =item quarter_stand_alone_abbreviated
903              
904             =item quarter_stand_alone_narrow
905              
906             All the above return an arrayref of quarter names in the requested style.
907              
908             =item am_pm_wide
909              
910             =item am_pm_abbreviated
911              
912             =item am_pm_narrow
913              
914             All the above return the date period name for AM and PM
915             in the requested style
916              
917             =item era_wide
918              
919             =item era_abbreviated
920              
921             =item era_narrow
922              
923             All the above return an array ref of era names. Note that these
924             return the first two eras which is what you normally want for
925             BC and AD etc. but won't work correctly for Japanese calendars.
926              
927             =back
928              
929             =cut
930              
931             foreach my $property (qw(
932             month_format_wide month_format_abbreviated month_format_narrow
933             month_stand_alone_wide month_stand_alone_abbreviated month_stand_alone_narrow
934             day_format_wide day_format_abbreviated day_format_narrow
935             day_stand_alone_wide day_stand_alone_abbreviated day_stand_alone_narrow
936             quarter_format_wide quarter_format_abbreviated quarter_format_narrow
937             quarter_stand_alone_wide quarter_stand_alone_abbreviated quarter_stand_alone_narrow
938             am_pm_wide am_pm_abbreviated am_pm_narrow
939             era_wide era_abbreviated era_narrow
940             era_format_wide era_format_abbreviated era_format_narrow
941             era_stand_alone_wide era_stand_alone_abbreviated era_stand_alone_narrow
942             )) {
943             has $property => (
944             is => 'ro',
945             isa => ArrayRef,
946             init_arg => undef,
947             lazy => 1,
948             builder => "_build_$property",
949             clearer => "_clear_$property",
950             );
951             }
952              
953             =pod
954              
955             The next set of methods are not used by DateTime::Locale but CLDR provide
956             the data and you might want it
957              
958             =over 4
959              
960             =item am_pm_format_wide
961              
962             =item am_pm_format_abbreviated
963              
964             =item am_pm_format_narrow
965              
966             =item am_pm_stand_alone_wide
967              
968             =item am_pm_stand_alone_abbreviated
969              
970             =item am_pm_stand_alone_narrow
971              
972             All the above return a hashref keyed on date period
973             with the value being the value for that date period
974              
975             =item era_format_wide
976              
977             =item era_format_abbreviated
978              
979             =item era_format_narrow
980            
981             =item era_stand_alone_wide
982              
983             =item era_stand_alone_abbreviated
984              
985             =item era_stand_alone_narrow
986              
987             All the above return an array ref with I<all> the era data for the
988             locale formatted to the requested width
989              
990             =cut
991              
992             foreach my $property (qw(
993             am_pm_format_wide am_pm_format_abbreviated am_pm_format_narrow
994             am_pm_stand_alone_wide am_pm_stand_alone_abbreviated am_pm_stand_alone_narrow
995             )) {
996             has $property => (
997             is => 'ro',
998             isa => HashRef,
999             init_arg => undef,
1000             lazy => 1,
1001             builder => "_build_$property",
1002             clearer => "_clear_$property",
1003             );
1004             }
1005              
1006             =item date_format_full
1007              
1008             =item date_format_long
1009              
1010             =item date_format_medium
1011              
1012             =item date_format_short
1013              
1014             =item time_format_full
1015              
1016             =item time_format_long
1017              
1018             =item time_format_medium
1019              
1020             =item time_format_short
1021              
1022             =item datetime_format_full
1023              
1024             =item datetime_format_long
1025              
1026             =item datetime_format_medium
1027              
1028             =item datetime_format_short
1029              
1030             All the above return the CLDR I<date format pattern> for the given
1031             element and width
1032              
1033             =cut
1034              
1035             foreach my $property (qw(
1036             id
1037             date_format_full date_format_long
1038             date_format_medium date_format_short
1039             time_format_full time_format_long
1040             time_format_medium time_format_short
1041             datetime_format_full datetime_format_long
1042             datetime_format_medium datetime_format_short
1043             )) {
1044             has $property => (
1045             is => 'ro',
1046             isa => Str,
1047             init_arg => undef,
1048             lazy => 1,
1049             builder => "_build_$property",
1050             clearer => "_clear_$property",
1051             );
1052             }
1053              
1054             has 'available_formats' => (
1055             is => 'ro',
1056             isa => ArrayRef,
1057             init_arg => undef,
1058             lazy => 1,
1059             builder => "_build_available_formats",
1060             clearer => "_clear_available_formats",
1061             );
1062              
1063             around available_formats => sub {
1064             my ($orig, $self) = @_;
1065             my $formats = $self->$orig;
1066            
1067             return @{$formats};
1068             };
1069              
1070             has 'format_data' => (
1071             is => 'ro',
1072             isa => HashRef,
1073             init_arg => undef,
1074             lazy => 1,
1075             builder => "_build_format_data",
1076             clearer => "_clear_format_data",
1077             );
1078              
1079             # default_calendar
1080             foreach my $property (qw(
1081             default_date_format_length default_time_format_length
1082             )) {
1083             has $property => (
1084             is => 'ro',
1085             isa => Str,
1086             init_arg => undef,
1087             lazy => 1,
1088             builder => "_build_$property",
1089             writer => "set_$property"
1090             );
1091             }
1092              
1093             =item prefers_24_hour_time()
1094              
1095             Returns a boolean value, true if the locale has a preference
1096             for 24 hour time over 12 hour
1097              
1098             =cut
1099              
1100             has 'prefers_24_hour_time' => (
1101             is => 'ro',
1102             isa => Bool,
1103             init_arg => undef,
1104             lazy => 1,
1105             builder => "_build_prefers_24_hour_time",
1106             );
1107              
1108             =item first_day_of_week()
1109              
1110             Returns the numeric representation of the first day of the week
1111             With 0 = Saturday
1112              
1113             =item get_day_period($time, $type = 'default')
1114              
1115             This method will calculate the correct
1116             period for a given time and return the period name in
1117             the locale's language and script
1118              
1119             =item format_for($date_time_format)
1120              
1121             This method takes a CLDR date time format and returns
1122             the localised version of the format.
1123              
1124             =cut
1125              
1126             has 'first_day_of_week' => (
1127             is => 'ro',
1128             isa => Int,
1129             init_arg => undef,
1130             lazy => 1,
1131             builder => "_build_first_day_of_week",
1132             );
1133              
1134             has 'likely_subtag' => (
1135             is => 'ro',
1136             isa => InstanceOf['Locale::CLDR'],
1137             init_arg => undef,
1138             writer => '_set_likely_subtag',
1139             predicate => '_has_likely_subtag',
1140             );
1141              
1142             my ($self, $what) = @_;
1143              
1144             my $vars = $self->_build_break_vars($what);
1145             my $rules = $self->_build_break_rules($vars, $what);
1146             return $rules;
1147             }
1148 4     4   9  
1149             my ($self, $what) = @_;
1150 4         21  
1151 4         25 my $name = "${what}_variables";
1152 4         140 my @bundles = $self->_find_bundle($name);
1153             my @vars;
1154             foreach my $bundle (reverse @bundles) {
1155             push @vars, @{$bundle->$name};
1156 4     4   11 }
1157              
1158 4         9 my %vars = ();
1159 4         18 while (my ($name, $value) = (shift @vars, shift @vars)) {
1160 4         27 last unless defined $name;
1161 4         11 if (! defined $value) {
1162 4         8 delete $vars{$name};
  4         86  
1163             next;
1164             }
1165 4         9  
1166 4         18 $value =~ s{ ( \$ \p{ID_START} \p{ID_CONTINUE}* ) }{$vars{$1}}msxeg;
1167 174 100       229 $vars{$name} = $value;
1168 170 50       190 }
1169 0         0  
1170 0         0 return \%vars;
1171             }
1172              
1173 170         278 return '';
  185         394  
1174 170         392 }
1175              
1176             # Test for missing Unicode properties
1177 4         15 my $has_emoji = eval '1 !~ /\p{emoji}/';
1178             my $has_Grapheme_Cluster_Break_ZWJ = eval '1 !~ /\p{Grapheme_Cluster_Break=ZWJ}/';
1179             my $has_Grapheme_Cluster_Break_E_Base = eval '1 !~ /\p{Grapheme_Cluster_Break=E_Base}/';
1180             my $has_Grapheme_Cluster_Break_E_Base_GAZ = eval '1 !~ /\p{Grapheme_Cluster_Break=E_Base_GAZ}/';
1181 460     460 0 140584 my $has_Grapheme_Cluster_Break_E_Modifier = eval '1 !~ /\p{Grapheme_Cluster_Break=E_Modifier}/';
1182             my $has_Word_Break_ZWJ = eval '1 !~ /\p{Word_Break=ZWJ}/';
1183             my $has_Word_Break_E_Base = eval '1 !~ /\p{Word_Break=E_Base}/';
1184             my $has_Word_Break_E_Base_GAZ = eval '1 !~ /\p{Word_Break=E_Base_GAZ}/';
1185             my $has_Word_Break_E_Modifier = eval '1 !~ /\p{Word_Break=E_Modifier}/';
1186             my $has_Word_Break_Hebrew_Letter = eval '1 !~ \p{Word_Break=Hebrew_Letter}/';
1187             my $has_Word_Break_Single_Quote = eval '1 !~ \p{Word_Break=Single_Quote}/';
1188             my $has_Line_Break_ZWJ = eval '1 !~ /\p{Line_Break=ZWJ}/';
1189             my $has_Line_Break_E_Base = eval '1 !~ /\p{Line_Break=E_Base}/';
1190             my $has_Line_Break_E_Base_GAZ = eval '1 !~ /\p{Line_Break=E_Base_GAZ}/';
1191             my $has_Line_Break_E_Modifier = eval '1 !~ /\p{Line_Break=E_Modifier}/';
1192             my $has_Extended_Pictographic = eval '1 !~ /\p{Extended_Pictographic}/';
1193             my $has_Word_Break_WSegSpace = eval '1 !~ /\p{Word_Break=WSegSpace}/';
1194              
1195             my $regex = shift;
1196            
1197             return '' unless defined $regex;
1198            
1199             $regex =~ s/\\(p)\{emoji\}/\\${1}{IsCLDREmpty}/ig
1200             unless $has_emoji;
1201            
1202             $regex =~ s/\\(p)\{Grapheme_Cluster_Break=ZWJ\}/\\${1}{IsCLDREmpty}/ig
1203             unless $has_Grapheme_Cluster_Break_ZWJ;
1204 341     341   464
1205             $regex =~ s/\\(p)\{Grapheme_Cluster_Break=E_Base\}/\\${1}{IsCLDREmpty}/ig
1206 341 100       477 unless $has_Grapheme_Cluster_Break_E_Base;
1207            
1208 340 50       906 $regex =~ s/\\(p)\{Grapheme_Cluster_Break=E_Base_GAZ\}/\\${1}{IsCLDREmpty}/ig
1209             unless $has_Grapheme_Cluster_Break_E_Base_GAZ;
1210              
1211 340 50       533 $regex =~ s/\\(p)\{Grapheme_Cluster_Break=E_Modifier\}/\\${1}{IsCLDREmpty}/ig
1212             unless $has_Grapheme_Cluster_Break_E_Modifier;
1213            
1214 340 50       484 $regex =~ s/\\(p)\{Word_Break=ZWJ\}/\\${1}{IsCLDREmpty}/ig
1215             unless $has_Word_Break_ZWJ;
1216              
1217 340 50       442 $regex =~ s/\\(p)\{Word_Break=E_Base\}/\\${1}{IsCLDREmpty}/ig
1218             unless $has_Word_Break_E_Base;
1219              
1220 340 50       437 $regex =~ s/\\(p)\{Word_Break=E_Base_GAZ\}/\\${1}{IsCLDREmpty}/ig
1221             unless $has_Word_Break_E_Base_GAZ;
1222              
1223 340 50       410 $regex =~ s/\\(p)\{Word_Break=E_Modifier\}/\\${1}{IsCLDREmpty}/ig
1224             unless $has_Word_Break_E_Modifier;
1225              
1226 340 50       461 $regex =~ s/\\(p)\{Word_Break=Hebrew_Letter\}/\\${1}{IsCLDREmpty}/ig
1227             unless $has_Word_Break_Hebrew_Letter;
1228              
1229 340 50       445 $regex =~ s/\\(p)\{Word_Break=Single_Quote\}/\\${1}{IsCLDREmpty}/ig
1230             unless $has_Word_Break_Single_Quote;
1231            
1232 340 50       465 $regex =~ s/\\(p)\{Line_Break=ZWJ\}/\\${1}{IsCLDREmpty}/ig
1233             unless $has_Line_Break_ZWJ;
1234              
1235 340 50       663 $regex =~ s/\\(p)\{Line_Break=E_Base\}/\\${1}{IsCLDREmpty}/ig
1236             unless $has_Line_Break_E_Base;
1237              
1238 340 50       643 $regex =~ s/\\(p)\{Line_Break=E_Base_GAZ\}/\\${1}{IsCLDREmpty}/ig
1239             unless $has_Line_Break_E_Base_GAZ;
1240              
1241 340 50       449 $regex =~ s/\\(p)\{Line_Break=E_Modifier\}/\\${1}{IsCLDREmpty}/ig
1242             unless $has_Line_Break_E_Modifier;
1243              
1244 340 50       467 $regex =~ s/\\(p)\{Extended_Pictographic\}/\\${1}{IsCLDREmpty}/ig
1245             unless $has_Extended_Pictographic;
1246            
1247 340 50       628 $regex =~ s/\\(p)\{Word_Break=WSegSpace\}/\\${1}{IsCLDREmpty}/ig
1248             unless $has_Word_Break_WSegSpace;
1249            
1250 340 50       439 return $regex;
1251             }
1252              
1253 340 50       613 my ($self, $vars, $what) = @_;
1254              
1255             my $name = "${what}_rules";
1256 340 50       572 my @bundles = $self->_find_bundle($name);
1257              
1258             my %rules;
1259 340         938 foreach my $bundle (reverse @bundles) {
1260             %rules = (%rules, %{$bundle->$name});
1261             }
1262              
1263 4     4   13 my @rules;
1264             foreach my $rule_number ( sort { $a <=> $b } keys %rules ) {
1265 4         8 # Test for deleted rules
1266 4         13 next unless defined $rules{$rule_number};
1267              
1268 4         29 $rules{$rule_number} =~ s{ ( \$ \p{ID_START} \p{ID_CONTINUE}* ) }{ _fix_missing_unicode_properties($vars->{$1}) }msxeg;
1269 4         9 my ($first, $opp, $second) = split /(×|÷)/, $rules{$rule_number};
1270 4         12  
  4         127  
1271             foreach my $operand ($first, $second) {
1272             if ($operand =~ m{ \S }msx) {
1273 4         9 $operand = _unicode_to_perl($operand);
1274 4         32 }
  444         408  
1275             else {
1276 112 50       361 $operand = '.';
1277             }
1278 112         624 }
  337         858  
1279 112         901
1280             no warnings 'deprecated';
1281 112         219 push @rules, [qr{$first}msx, qr{$second}msx, ($opp eq '×' ? 1 : 0)];
1282 224 100       64061 }
1283 189         3208  
1284             push @rules, [ '.', '.', 0 ];
1285              
1286 35         56 return \@rules;
1287             }
1288              
1289             my $self = shift;
1290 21     21   49372 my %args;
  21         39  
  21         28311  
1291 112 100       61828  
1292             # Used for arguments when we call new from our own code
1293             my %internal_args = ();
1294 4         34 if (@_ > 1 && ref $_[-1] eq 'HASH') {
1295             %internal_args = %{pop @_};
1296 4         82 }
1297              
1298             if (1 == @_ && ! ref $_[0]) {
1299             my ($language, $script, $region, $variant, $extensions)
1300 106     106 0 460773 = $_[0]=~/^
1301 106         247 ([a-zA-Z]+)
1302             (?:[-_]([a-zA-Z]{4}))?
1303             (?:[-_]([a-zA-Z]{2,3}))?
1304 106         261 (?:[-_]([a-zA-Z0-9]+))?
1305 106 50 66     667 (?:[-_]u[_-](.+))?
1306 0         0 $/x;
  0         0  
1307              
1308             if (! defined $script && length $language == 4) {
1309 106 100 66     702 $script = $language;
1310 85         757 $language = undef;
1311             }
1312            
1313             foreach ($language, $script, $region, $variant) {
1314             $_ = '' unless defined $_;
1315             }
1316              
1317             %args = (
1318             language_id => $language,
1319 85 100 100     477 script_id => $script,
1320 1         2 region_id => $region,
1321 1         2 variant_id => $variant,
1322             extensions => $extensions,
1323             );
1324 85         265 }
1325 340 100       622  
1326             if (! keys %args ) {
1327             %args = ref $_[0]
1328             ? %{$_[0]}
1329 85         548 : @_
1330             }
1331              
1332             # Split up the extensions
1333             if ( defined $args{extensions} && ! ref $args{extensions} ) {
1334             $args{extensions} = {
1335             map {lc}
1336             split /[_-]/, $args{extensions}
1337 106 100       409 };
1338             }
1339 21 50       134  
  0         0  
1340             # Fix casing of args
1341             $args{language_id} = lc $args{language_id} if defined $args{language_id};
1342             $args{script_id} = ucfirst lc $args{script_id} if defined $args{script_id};
1343             $args{region_id} = uc $args{region_id} if defined $args{region_id};
1344 106 100 66     491 $args{variant_id} = uc $args{variant_id} if defined $args{variant_id};
1345            
1346 16         48 # Set up undefined language
1347             $args{language_id} ||= 'und';
1348 6         34  
1349             $self->SUPER::BUILDARGS(%args, %internal_args);
1350             }
1351              
1352 106 100       537 my ($self, $args) = @_;
1353 106 100       584  
1354 106 100       460 # Check that the args are valid
1355 106 100       467 # also check for aliases
1356             $args->{language_id} = $self->language_aliases->{$args->{language_id}}
1357             // $args->{language_id};
1358 106   100     348
1359             die "Invalid language" if $args->{language_id}
1360 106         843 && ! first { $args->{language_id} eq $_ } $self->valid_languages;
1361              
1362             die "Invalid script" if $args->{script_id}
1363             && ! first { ucfirst lc $args->{script_id} eq ucfirst lc $_ } $self->valid_scripts;
1364              
1365             die "Invalid region" if $args->{region_id}
1366             && ( ! ( first { uc $args->{region_id} eq uc $_ } $self->valid_regions )
1367             && ( ! $self->region_aliases->{$self->{region_id}} )
1368             );
1369            
1370             die "Invalid variant" if $args->{variant_id}
1371             && ( ! ( first { uc $args->{variant_id} eq uc $_ } $self->valid_variants )
1372             && ( ! $self->variant_aliases->{lc $self->{variant_id}} )
1373             );
1374            
1375             if ($args->{extensions}) {
1376             my %valid_keys = $self->valid_keys;
1377             my %key_aliases = $self->key_names;
1378             my @keys = keys %{$args->{extensions}};
1379              
1380             foreach my $key ( @keys ) {
1381             my $canonical_key = exists $key_aliases{$key} ? $key_aliases{$key} : undef;
1382             $canonical_key //= $key;
1383             if ($canonical_key ne $key) {
1384             $args->{extensions}{$canonical_key} = delete $args->{extensions}{$key};
1385             }
1386              
1387             $key = $canonical_key;
1388             die "Invalid extension name" unless exists $valid_keys{$key};
1389             die "Invalid extension value" unless
1390             first { $_ eq $args->{extensions}{$key} } @{$valid_keys{$key}};
1391             }
1392              
1393             $self->_set_extensions($args->{extensions});
1394             }
1395              
1396             # Check for variant aliases
1397             if ($args->{variant_id} && (my $variant_alias = $self->variant_aliases->{lc $self->variant_id})) {
1398             delete $args->{variant_id};
1399             my ($what) = keys %{$variant_alias};
1400             my ($value) = values %{$variant_alias};
1401             $args->{$what} = $value;
1402             }
1403            
1404             # Now set up the module
1405             $self->_build_module;
1406             }
1407              
1408             after 'BUILD' => sub {
1409              
1410             my $self = shift;
1411            
1412             # Fix up likely sub tags
1413            
1414             my $likely_subtags = $self->likely_subtags;
1415             my $likely_subtag;
1416             my ($language_id, $script_id, $region_id) = ($self->language_id, $self->script_id, $self->region_id);
1417            
1418             unless ($language_id ne 'und' && $script_id && $region_id ) {
1419             $likely_subtag = $likely_subtags->{join '_', grep { length() } ($language_id, $script_id, $region_id)};
1420            
1421             if (! $likely_subtag ) {
1422             $likely_subtag = $likely_subtags->{join '_', $language_id, $region_id};
1423             }
1424            
1425             if (! $likely_subtag ) {
1426             $likely_subtag = $likely_subtags->{join '_', $language_id, $script_id};
1427             }
1428            
1429             if (! $likely_subtag ) {
1430             $likely_subtag = $likely_subtags->{$language_id};
1431             }
1432            
1433             if (! $likely_subtag ) {
1434             $likely_subtag = $likely_subtags->{join '_', 'und', $script_id};
1435             }
1436             }
1437            
1438             my ($likely_language_id, $likely_script_id, $likely_region_id);
1439             if ($likely_subtag) {
1440             ($likely_language_id, $likely_script_id, $likely_region_id) = split /_/, $likely_subtag;
1441             $likely_language_id = $language_id unless $language_id eq 'und';
1442             $likely_script_id = $script_id if length $script_id;
1443             $likely_region_id = $region_id if length $region_id;
1444             $self->_set_likely_subtag(__PACKAGE__->new(join '_',$likely_language_id, $likely_script_id, $likely_region_id));
1445             }
1446            
1447             # Fix up extension overrides
1448             my $extensions = $self->extensions;
1449            
1450             foreach my $extention ( qw( ca cf co cu em fw hc lb lw ms nu rg sd ss tz va ) ) {
1451             if (exists $extensions->{$extention}) {
1452             my $default = "_set_default_$extention";
1453             $self->$default($extensions->{$extention});
1454             }
1455             }
1456             };
1457              
1458             # Defaults get set by the -u- extension
1459             # Calendar, currency format, collation order, etc.
1460             # but not nu as that is done in the Numbering systems role
1461             foreach my $default (qw( ca cf co cu em fw hc lb lw ms rg sd ss tz va)) {
1462             has "_default_$default" => (
1463             is => 'ro',
1464             isa => Str,
1465             init_arg => undef,
1466             default => '',
1467             writer => "_set_default_$default",
1468             );
1469            
1470             no strict 'refs';
1471             *{"_test_default_$default"} = sub {
1472             my $self = shift;
1473             my $method = "_default_$default";
1474             return length $self->$method;
1475             };
1476             }
1477              
1478             my ($self, $region) = @_;
1479              
1480             my $default = '';
1481             if ($self->_test_default_ca) {
1482 21     21   159 $default = $self->_default_ca();
  21         44  
  21         7607  
1483             }
1484 108     108   147 else {
1485 108         222 my $calendar_preferences = $self->calendar_preferences();
1486 108         534 $region //= ( $self->region_id() || $self->likely_subtag->region_id );
1487             my $current_region = $region;
1488              
1489             while (! $default) {
1490             $default = $calendar_preferences->{$current_region};
1491 68     68 1 127 if ($default) {
1492             $default = $default->[0];
1493 68         112 }
1494 68 100       174 else {
1495 66         116 $current_region = $self->region_contained_by()->{$current_region}
1496             }
1497             }
1498 2         11 $self->_set_default_ca($default);
1499 2   33     42 }
      33        
1500 2         4 return $default;
1501             }
1502 2         8  
1503 10         17 my $self = shift;
1504 10 100       15
1505 2         6 my $default = 'standard';
1506             if ($self->_test_default_cf) {
1507             $default = $self->_default_cf();
1508 8         24 }
1509             else {
1510             $self->_set_default_cf($default);
1511 2         31 }
1512            
1513 68         168 return $default;
1514             }
1515              
1516             use overload
1517 20     20 1 53 'bool' => sub { 1 },
1518             '""' => sub {shift->id};
1519 20         52  
1520 20 50       117 my $self = shift;
1521 20         190 my $string = lc $self->language_id;
1522              
1523             if ($self->script_id) {
1524 0         0 $string.= '_' . ucfirst lc $self->script_id;
1525             }
1526              
1527 20         79 if ($self->region_id) {
1528             $string.= '_' . uc $self->region_id;
1529             }
1530              
1531 40     40   117 if ($self->variant_id) {
1532 21     21   138 $string.= '_' . uc $self->variant_id;
  21     3   38  
  21         266  
  3         1380  
1533             }
1534              
1535 36     36   47390 if (defined $self->extensions) {
1536 36         651 $string.= '_u';
1537             foreach my $key (sort keys %{$self->extensions}) {
1538 36 100       173 my $value = $self->extensions->{$key};
1539 28         174 $string .= "_${key}_$value";
1540             }
1541             $string =~ s/_u$//;
1542 36 100       703 }
1543 28         397  
1544             return $string;
1545             }
1546 36 100       454  
1547 3         11 my $self = shift;
1548             my $english;
1549             if ($self->language_id eq 'en') {
1550 36 50       292 $english = $self;
1551 0         0 }
1552 0         0 else {
  0         0  
1553 0         0 $english = Locale::CLDR->new('en_Latn_US');
1554 0         0 }
1555              
1556 0         0 return $english;
1557             }
1558              
1559 36         477 my $self = shift;
1560              
1561             return $self->_get_english->native_name($self);
1562             }
1563 0     0   0  
1564 0         0 my ($self, $for) = @_;
1565 0 0       0  
1566 0         0 return $self->locale_name($for);
1567             }
1568              
1569 0         0 my $self = shift;
1570              
1571             return $self->_get_english->native_language($self);
1572 0         0 }
1573              
1574             my ($self, $for) = @_;
1575              
1576 0     0   0 return $self->language_name($for) // '';
1577             }
1578 0         0  
1579             my $self = shift;
1580              
1581             return $self->_get_english->native_script($self);
1582 0     0   0 }
1583              
1584 0         0 my ($self, $for) = @_;
1585              
1586             return $self->script_name($for);
1587             }
1588 0     0   0  
1589             my $self = shift;
1590 0         0  
1591             return $self->_get_english->native_region($self);
1592             }
1593              
1594 0     0   0 my ($self, $for) = @_;
1595              
1596 0   0     0 return $self->region_name($for);
1597             }
1598              
1599             my $self = shift;
1600 0     0   0  
1601             return $self->_get_english->native_variant($self);
1602 0         0 }
1603              
1604             my ($self, $for) = @_;
1605              
1606 0     0   0 return $self->variant_name($for);
1607             }
1608 0         0  
1609             # Method to locate the resource bundle with the required data
1610             my ($self, $method_name) = @_;
1611             my $id = $self->_has_likely_subtag()
1612 0     0   0 ? $self->likely_subtag()->id()
1613             : $self->id();
1614 0         0
1615            
1616             if ($self->method_cache->{$id}{$method_name}) {
1617             return wantarray
1618 0     0   0 ? @{$self->method_cache->{$id}{$method_name}}
1619             : $self->method_cache->{$id}{$method_name}[0];
1620 0         0 }
1621              
1622             foreach my $module (@{mro::get_linear_isa( ref ($self->module ))}) {
1623             last if $module eq 'Moo::Object';
1624 0     0   0 if (defined &{"${module}::${method_name}"}) {
1625             push @{$self->method_cache->{$id}{$method_name}}, $module->new;
1626 0         0 }
1627             }
1628              
1629             return unless $self->method_cache->{$id}{$method_name};
1630 0     0   0 return wantarray
1631             ? @{$self->method_cache->{$id}{$method_name}}
1632 0         0 : $self->method_cache->{$id}{$method_name}[0];
1633             }
1634              
1635             =back
1636              
1637 3363     3363   4504 =head2 Names
1638 3363 50       51615  
1639             These methods allow you to pass in a locale, either by C<id> or as a
1640             Locale::CLDR object and return an name formatted in the locale of $self.
1641             If you don't pass in a locale then it will use $self.
1642              
1643 3363 100       54566 =over 4
1644              
1645 2451         25669 =item locale_name($name)
1646 3230 100       24368  
1647             Returns the given locale name in the current locale's format. The name can be
1648             a locale id or a locale object or non existent. If a name is not passed in
1649 133         1597 then the name of the current locale is returned.
  133         1836  
1650 665 100       7847  
1651 532 100       573 =cut
  532         2839  
1652 123         198  
  123         1865  
1653             my ($self, $name) = @_;
1654             $name //= $self;
1655              
1656 133 100       2080 my $code = ref $name
1657             ? join ( '_', $name->language_id, $name->region_id ? $name->region_id : () )
1658 66         825 : $name;
1659 81 100       1133
1660             my @bundles = $self->_find_bundle('display_name_language');
1661              
1662             foreach my $bundle (@bundles) {
1663             my $display_name = $bundle->display_name_language->($code);
1664             return $display_name if defined $display_name;
1665             }
1666              
1667             # $name can be a string or a Locale::CLDR::Locales::*
1668             if (! ref $name) {
1669             # Wrap in an eval to stop it dieing on unknown locales
1670             $name = eval { Locale::CLDR->new($name) };
1671             }
1672              
1673             # Now we have to process each individual element
1674             # to pass to the display name pattern
1675             my $language = $self->language_name($name);
1676             my $script = $self->script_name($name);
1677             my $region = $self->region_name($name);
1678             my $variant = $self->variant_name($name);
1679              
1680             my $bundle = $self->_find_bundle('display_name_pattern');
1681 6     6 1 2426 return $bundle
1682 6   66     29 ->display_name_pattern($language, $region, $script, $variant);
1683             }
1684 6 50       43  
    100          
1685             =item language_name($language)
1686              
1687             Returns the language name in the current locale's format. The name can be
1688 6         28 a locale language id or a locale object or non existent. If a name is not
1689             passed in then the language name of the current locale is returned.
1690 6         43  
1691 6         37 =cut
1692 6 100       49  
1693             my ($self, $name) = @_;
1694              
1695             $name //= $self;
1696 2 50       8  
1697             my $code = ref $name ? $name->language_id : eval { Locale::CLDR->new(language_id => $name)->language_id };
1698 2         5  
  2         49  
1699             my $language = undef;
1700             my @bundles = $self->_find_bundle('display_name_language');
1701             if ($code) {
1702             foreach my $bundle (@bundles) {
1703 2         2705 my $display_name = $bundle->display_name_language->($code);
1704 2         12 if (defined $display_name) {
1705 2         11 $language = $display_name;
1706 2         11 last;
1707             }
1708 2         9 }
1709 2         24 }
1710             # If we don't have a display name for the language we try again
1711             # with the und tag
1712             if (! defined $language ) {
1713             foreach my $bundle (@bundles) {
1714             my $display_name = $bundle->display_name_language->('und');
1715             if (defined $display_name) {
1716             $language = $display_name;
1717             last;
1718             }
1719             }
1720             }
1721              
1722 8     8 1 24 return $language;
1723             }
1724 8   66     46  
1725             =item all_languages()
1726 8 100       148  
  3         93  
1727             Returns a hash ref keyed on language id of all the languages the system
1728 8         10396 knows about. The values are the language names for the corresponding id's
1729 8         61  
1730 8 100       70 =cut
1731 7         21  
1732 7         54 my $self = shift;
1733 7 50       31  
1734 7         16 my @bundles = $self->_find_bundle('display_name_language');
1735 7         18 my %languages;
1736             foreach my $bundle (@bundles) {
1737             my $languages = $bundle->display_name_language->();
1738              
1739             # Remove existing languages
1740             delete @{$languages}{keys %languages};
1741 8 100       34  
1742 1         4 # Assign new ones to the hash
1743 1         15 @languages{keys %$languages} = values %$languages;
1744 1 50       6 }
1745 1         3  
1746 1         4 return \%languages;
1747             }
1748              
1749             =item script_name($script)
1750              
1751 8         57 Returns the script name in the current locale's format. The script can be
1752             a locale script id or a locale object or non existent. If a script is not
1753             passed in then the script name of the current locale is returned.
1754              
1755             =cut
1756              
1757             my ($self, $name) = @_;
1758             $name //= $self;
1759              
1760             if (! ref $name ) {
1761             $name = eval {__PACKAGE__->new(script_id => $name)};
1762 1     1 1 2 }
1763              
1764 1         4 if ( ref $name && ! $name->script_id ) {
1765 1         8 return '';
1766 1         3 }
1767 1         6  
1768             my $script = undef;
1769             my @bundles = $self->_find_bundle('display_name_script');
1770 1         5 if ($name) {
  1         2  
1771             foreach my $bundle (@bundles) {
1772             $script = $bundle->display_name_script->($name->script_id);
1773 1         214 if (defined $script) {
1774             last;
1775             }
1776 1         8 }
1777             }
1778              
1779             if (! $script) {
1780             foreach my $bundle (@bundles) {
1781             $script = $bundle->display_name_script->('Zzzz');
1782             if (defined $script) {
1783             last;
1784             }
1785             }
1786             }
1787              
1788 7     7 1 24 return $script;
1789 7   66     35 }
1790              
1791 7 100       27 =item all_scripts()
1792 3         5  
  3         82  
1793             Returns a hash ref keyed on script id of all the scripts the system
1794             knows about. The values are the script names for the corresponding id's
1795 7 100 100     5763  
1796 3         12 =cut
1797              
1798             my $self = shift;
1799 4         20  
1800 4         27 my @bundles = $self->_find_bundle('display_name_script');
1801 4 100       46 my %scripts;
1802 3         7 foreach my $bundle (@bundles) {
1803 3         33 my $scripts = $bundle->display_name_script->();
1804 3 50       10  
1805 3         8 # Remove existing scripts
1806             delete @{$scripts}{keys %scripts};
1807              
1808             # Assign new ones to the hash
1809             @scripts{keys %$scripts} = values %$scripts;
1810 4 100       17 }
1811 1         4  
1812 1         14 return \%scripts;
1813 1 50       4 }
1814 1         5  
1815             =item region_name($region)
1816              
1817             Returns the region name in the current locale's format. The region can be
1818             a locale region id or a locale object or non existent. If a region is not
1819 4         9302 passed in then the region name of the current locale is returned.
1820              
1821             =cut
1822              
1823             my ($self, $name) = @_;
1824             $name //= $self;
1825              
1826             if (! ref $name ) {
1827             $name = eval { __PACKAGE__->new(language_id => 'und', region_id => $name); };
1828             }
1829              
1830 1     1 1 3 if ( ref $name && ! $name->region_id) {
1831             return '';
1832 1         5 }
1833 1         8  
1834 1         3 my $region = undef;
1835 1         6 my @bundles = $self->_find_bundle('display_name_region');
1836             if ($name) {
1837             foreach my $bundle (@bundles) {
1838 1         4 $region = $bundle->display_name_region->{$name->region_id};
  1         3  
1839             if (defined $region) {
1840             last;
1841 1         56 }
1842             }
1843             }
1844 1         8  
1845             if (! defined $region) {
1846             foreach my $bundle (@bundles) {
1847             $region = $bundle->display_name_region->{'ZZ'};
1848             if (defined $region) {
1849             last;
1850             }
1851             }
1852             }
1853              
1854             return $region;
1855             }
1856 9     9 1 33  
1857 9   66     41 =item all_regions
1858              
1859 9 100       40 Returns a hash ref keyed on region id of all the region the system
1860 5         12 knows about. The values are the region names for the corresponding ids
  5         128  
1861              
1862             =cut
1863 9 50 66     13942  
1864 0         0 my $self = shift;
1865              
1866             my @bundles = $self->_find_bundle('display_name_region');
1867 9         29 my %regions;
1868 9         54 foreach my $bundle (@bundles) {
1869 9 100       99 my $regions = $bundle->display_name_region;
1870 7         24  
1871 7         134 # Remove existing regions
1872 7 50       32 delete @{$regions}{keys %regions};
1873 7         20  
1874             # Assign new ones to the hash
1875             @regions{keys %$regions} = values %$regions;
1876             }
1877              
1878 9 100       53 return \%regions;
1879 2         7 }
1880 2         14  
1881 2 50       7 =item variant_name($variant)
1882 2         4  
1883             Returns the variant name in the current locale's format. The variant can be
1884             a locale variant id or a locale object or non existent. If a variant is not
1885             passed in then the variant name of the current locale is returned.
1886              
1887 9         19729 =cut
1888              
1889             my ($self, $name) = @_;
1890             $name //= $self;
1891              
1892             if (! ref $name ) {
1893             $name = __PACKAGE__->new(language_id=> 'und', variant_id => $name);
1894             }
1895              
1896             return '' unless $name->variant_id;
1897             my $variant = undef;
1898 1     1 1 2 if ($name->has_variant) {
1899             my @bundles = $self->_find_bundle('display_name_variant');
1900 1         5 foreach my $bundle (@bundles) {
1901 1         8 $variant= $bundle->display_name_variant->{$name->variant_id};
1902 1         3 if (defined $variant) {
1903 1         5 last;
1904             }
1905             }
1906 1         3 }
  1         2  
1907              
1908             return $variant // '';
1909 1         153 }
1910              
1911             =item key_name($key)
1912 1         9  
1913             Returns the key name in the current locale's format. The key must be
1914             a locale key id as a string
1915              
1916             =cut
1917              
1918             my ($self, $key) = @_;
1919              
1920             $key = lc $key;
1921            
1922             my %key_aliases = $self->key_aliases;
1923             my %key_names = $self->key_names;
1924 7     7 1 71 my %valid_keys = $self->valid_keys;
1925 7   66     29  
1926             my $alias = $key_aliases{$key} // '';
1927 7 100       27 my $name = $key_names{$key} // '';
1928 4         100  
1929             return '' unless exists $valid_keys{$key} || exists $valid_keys{$alias} || exists $valid_keys{$name};
1930             my @bundles = $self->_find_bundle('display_name_key');
1931 6 100       6157 foreach my $bundle (@bundles) {
1932 3         10 my $return = $bundle->display_name_key->{$key};
1933 3 50       21 $return //= $bundle->display_name_key->{$alias};
1934 3         19 $return //= $bundle->display_name_key->{$name};
1935 3         29  
1936 3         28 return $return if defined $return && length $return;
1937 3 100       13 }
1938 2         7  
1939             return ucfirst ($key_names{$name} || $key_names{$alias} || $key_names{$key} || $key);
1940             }
1941              
1942             =item type_name($key, $type)
1943 3   100     20941  
1944             Returns the type name in the current locale's format. The key and type must be
1945             a locale key id and type id as a string
1946              
1947             =cut
1948              
1949             my ($self, $key, $type) = @_;
1950              
1951             $key = lc $key;
1952             $type = lc $type;
1953              
1954 3     3 1 14 my %key_aliases = $self->key_aliases;
1955             my %valid_keys = $self->valid_keys;
1956 3         11 my %key_names = $self->key_names;
1957              
1958 3         75 my $alias = $key_aliases{$key} // '';
1959 3         57 my $name = $key_names{$key} // '';
1960 3         67  
1961             return '' unless exists $valid_keys{$key} || $valid_keys{$alias} || $valid_keys{$name};
1962 3   100     23 return '' unless first { $_ eq $type } @{$valid_keys{$key} || []}, @{$valid_keys{$alias} || []}, @{$valid_keys{$name} || []};
1963 3   100     17  
1964             my @bundles = $self->_find_bundle('display_name_type');
1965 3 50 66     25 foreach my $bundle (@bundles) {
      33        
1966 3         18 my $types = $bundle->display_name_type->{$key} // $bundle->display_name_type->{$alias} // $bundle->display_name_type->{$name};
1967 3         28 my $type = $types->{$type};
1968 3         20 return $type if defined $type;
1969 3   66     19 }
1970 3   33     10  
1971             return '';
1972 3 50 33     99 }
1973            
1974             =item measurement_system_name($measurement_system)
1975 0   0     0  
1976             Returns the measurement system name in the current locale's format. The measurement system must be
1977             a measurement system id as a string
1978              
1979             =cut
1980            
1981             my ($self, $name) = @_;
1982              
1983             # Fix case of code
1984             $name = uc $name;
1985             $name = 'metric' if $name eq 'METRIC';
1986 3     3 1 14  
1987             my @bundles = $self->_find_bundle('display_name_measurement_system');
1988 3         12 foreach my $bundle (@bundles) {
1989 3         9 my $system = $bundle->display_name_measurement_system->{$name};
1990             return $system if defined $system;
1991 3         70 }
1992 3         88  
1993 3         56 return '';
1994             }
1995 3   100     30  
1996 3   100     16 =item transform_name($name)
1997              
1998 3 50 66     27 Returns the transform (transliteration) name in the current locale's format. The transform must be
      33        
1999 3 100   20   21 a transform id as a string
  20 50       32  
  3 100       19  
  3 50       23  
  3         28  
2000              
2001 3         21 =cut
2002 3         27  
2003 3   66     30 my ($self, $name) = @_;
      33        
2004 3         8  
2005 3 50       98 $name = lc $name;
2006              
2007             my @bundles = $self->_find_bundle('display_name_transform_name');
2008 0         0 foreach my $bundle (@bundles) {
2009             my $key = $bundle->display_name_transform_name->{$name};
2010             return $key if length $key;
2011             }
2012              
2013             return '';
2014             }
2015              
2016             =item code_pattern($type, $locale)
2017              
2018             This method formats a language, script or region name, given as C<$type>
2019 6     6 1 1700 from C<$locale> in a way expected by the current locale. If $locale is
2020             not passed in or is undef() the method uses the current locale.
2021              
2022 6         17 =cut
2023 6 100       28  
2024             my ($self, $type, $locale) = @_;
2025 6         25 $type = lc $type;
2026 6         47  
2027 6         31 return '' unless $type =~ m{ \A (?: language | script | region ) \z }x;
2028 6 50       49
2029             # If locale is not passed in then we are using ourself
2030             $locale //= $self;
2031 0         0  
2032             # If locale is not an object then inflate it
2033             $locale = __PACKAGE__->new($locale) unless blessed $locale;
2034              
2035             my $method = $type . '_name';
2036             my $substitute = $self->$method($locale);
2037              
2038             my @bundles = $self->_find_bundle('display_name_code_patterns');
2039             foreach my $bundle (@bundles) {
2040             my $text = $bundle->display_name_code_patterns->{$type};
2041             next unless defined $text;
2042 1     1 1 3 my $match = qr{ \{ 0 \} }x;
2043             $text=~ s{ $match }{$substitute}gxms;
2044 1         3 return $text;
2045             }
2046 1         4  
2047 1         8 return '';
2048 0         0 }
2049 0 0       0  
2050             =item text_orientation($type)
2051              
2052 1         6 Gets the text orientation for the locale. Type must be one of
2053             C<lines> or C<characters>
2054              
2055             =cut
2056              
2057             my $self = shift;
2058             my $type = shift;
2059              
2060             my @bundles = $self->_find_bundle('text_orientation');
2061             foreach my $bundle (@bundles) {
2062             my $orientation = $bundle->text_orientation;
2063             next unless defined $orientation;
2064 3     3 1 608 return $orientation->{$type};
2065 3         8 }
2066              
2067 3 50       19 return;
2068             }
2069              
2070 3   33     12 my ($self, $casing, $string) = @_;
2071              
2072             my @words = $self->split_words($string);
2073 3 50       16  
2074             if ($casing eq 'titlecase-firstword') {
2075 3         8 # Check to see whether $words[0] is white space or not
2076 3         12 my $firstword_location = 0;
2077             if ($words[0] =~ m{ \A \s }x) {
2078 3         10 $firstword_location = 1;
2079 3         22 }
2080 3         13  
2081 3 50       9 $words[$firstword_location] = ucfirst $words[$firstword_location];
2082 3         9 }
2083 3         29 elsif ($casing eq 'titlecase-words') {
2084 3         24 @words = map{ ucfirst } @words;
2085             }
2086             elsif ($casing eq 'lowercase-words') {
2087 0         0 @words = map{ lc } @words;
2088             }
2089              
2090             return join '', @words;
2091             }
2092              
2093             =back
2094              
2095             =head2 Segmentation
2096              
2097             This group of methods allow you to split a string in various ways
2098 2     2 1 1033 Note you need Perl 5.18 or above for this
2099 2         6  
2100             =over 4
2101 2         9  
2102 2         17 =item split_grapheme_clusters($string)
2103 2         9  
2104 2 50       7 Splits a string on grapheme clusters using the locale's segmentation rules.
2105 2         18 Returns a list of grapheme clusters.
2106              
2107             =cut
2108 0         0 # Need 5.18 and above
2109             die "You need Perl 5.18 or later for this functionality\n"
2110             if $^V lt v5.18.0;
2111             }
2112 0     0   0  
2113             _new_perl();
2114 0         0
2115             my ($self, $string) = @_;
2116 0 0       0  
    0          
    0          
2117             my $rules = $self->break_grapheme_cluster;
2118 0         0 my @clusters = $self->_split($rules, $string, 1);
2119 0 0       0  
2120 0         0 return @clusters;
2121             }
2122              
2123 0         0 =item split_words($string)
2124              
2125             Splits a string on word boundaries using the locale's segmentation rules.
2126 0         0 Returns a list of words.
  0         0  
2127              
2128             =cut
2129 0         0  
  0         0  
2130             _new_perl();
2131            
2132 0         0 my ($self, $string) = @_;
2133              
2134             my $rules = $self->break_word;
2135             my @words = $self->_split($rules, $string);
2136              
2137             return @words;
2138             }
2139              
2140             =item split_sentences($string)
2141              
2142             Splits a string on on all points where a sentence could
2143             end using the locale's segmentation rules. Returns a list
2144             the end of each list element is the point where a sentence
2145             could end.
2146              
2147             =cut
2148              
2149             _new_perl();
2150            
2151             my ($self, $string) = @_;
2152 11 50   11   105  
2153             my $rules = $self->break_sentence;
2154             my @sentences = $self->_split($rules, $string);
2155              
2156             return @sentences;
2157 1     1 1 987 }
2158              
2159 1         4 =item split_lines($string)
2160              
2161 1         22 Splits a string on on all points where a line could
2162 1         33 end using the locale's segmentation rules. Returns a list
2163             the end of each list element is the point where a line
2164 1         9 could end.
2165              
2166             =cut
2167              
2168             _new_perl();
2169            
2170             my ($self, $string) = @_;
2171              
2172             my $rules = $self->break_line;
2173             my @lines = $self->_split($rules, $string);
2174              
2175 1     1 1 1177 return @lines;
2176             }
2177 1         5  
2178             my ($self, $rules, $string, $grapheme_split) = @_;
2179 1         28  
2180 1         31 my @split = (scalar @$rules) x (length($string) - 1);
2181              
2182 1         6 pos($string)=0;
2183             # The Unicode Consortium has deprecated LB=Surrogate but the CLDR still
2184             # uses it, at least in this version.
2185             no warnings 'deprecated';
2186             while (length($string) -1 != pos $string) {
2187             my $rule_number = 0;
2188             my $first;
2189             foreach my $rule (@$rules) {
2190             unless( ($first) = $string =~ m{
2191             \G
2192             ($rule->[0])
2193             $rule->[1]
2194             }msx) {
2195 1     1 1 897 $rule_number++;
2196             next;
2197 1         5 }
2198             my $location = pos($string) + length($first) -1;
2199 1         29 $split[$location] = $rule_number;
2200 1         34
2201             # If the left hand side was part of a grapheme cluster
2202 1         5 # we have to jump past the entire cluster
2203             my $length = length $first;
2204             my ($gc) = $string =~ /\G(\X)/;
2205             $length = (! $grapheme_split && length($gc)) > $length ? length($gc) : $length;
2206             pos($string)+= $length;
2207             last;
2208             }
2209             }
2210              
2211             push @$rules,[undef,undef,1];
2212             @split = map {$rules->[$_][2] ? 1 : 0} @split;
2213             my $count = 0;
2214             my @sections = ('.');
2215 1     1 1 919 foreach my $split (@split) {
2216             $count++ unless $split;
2217 1         4 $sections[$count] .= '.';
2218             }
2219 1         29
2220 1         31 my $regex = _fix_missing_unicode_properties('(' . join(')(', @sections) . ')');
2221             $regex = qr{ \A $regex \z}msx;
2222 1         7 @split = $string =~ $regex;
2223              
2224             return @split;
2225             }
2226 4     4   11  
2227             =back
2228 4         57  
2229             =head2 Characters
2230 4         12  
2231             =over 4
2232              
2233 21     21   72138 =item is_exemplar_character( $type, $character)
  21         46  
  21         65989  
2234 4         17  
2235 160         288 =item is_exemplar_character($character)
2236 160         235  
2237 160         274 Tests if the given character is used in the locale. There are
2238 2950 100       44654 three possible types; C<main>, C<auxiliary> and C<punctuation>.
2239             If no type is given C<main> is assumed. Unless the C<index> type
2240             is given you will have to have a Perl version of 5.18 or above
2241             to use this method
2242              
2243 2790         2210126 =cut
2244 2790         16919  
2245             my ($self, @parameters) = @_;
2246 160         139938 unshift @parameters, 'main' if @parameters == 1;
2247 160         408  
2248             _new_perl() unless $parameters[0] eq 'index';
2249            
2250             my @bundles = $self->_find_bundle('characters');
2251 160         251 foreach my $bundle (@bundles) {
2252 160         677 my $characters = $bundle->characters->{lc $parameters[0]};
2253 160 100 66     973 next unless defined $characters;
2254 160         445 return 1 if fc($parameters[1])=~$characters;
2255 160         771 }
2256              
2257             return;
2258             }
2259 4         13  
2260 4 100       12 =item index_characters()
  164         237  
2261 4         8  
2262 4         10 Returns an array ref of characters normally used when creating
2263 4         9 an index and ordered appropriately.
2264 164 100       181  
2265 164         165 =cut
2266              
2267             my $self = shift;
2268 4         25  
2269 4         77 my @bundles = $self->_find_bundle('characters');
2270 4         38 foreach my $bundle (@bundles) {
2271             my $characters = $bundle->characters->{index};
2272 4         32 next unless defined $characters;
2273             return $characters;
2274             }
2275             return [];
2276             }
2277              
2278             my ($self, $type, @params) = @_;
2279              
2280             my @bundles = $self->_find_bundle('ellipsis');
2281             foreach my $bundle (@bundles) {
2282             my $ellipsis = $bundle->ellipsis->{$type};
2283             next unless defined $ellipsis;
2284             $ellipsis=~s{ \{ 0 \} }{$params[0]}msx;
2285             $ellipsis=~s{ \{ 1 \} }{$params[1]}msx;
2286             return $ellipsis;
2287             }
2288             }
2289              
2290             =back
2291              
2292             =head2 Truncation
2293              
2294 7     7 1 842 These methods format a string to show where part of the string has been removed
2295 7 100       18  
2296             =over 4
2297 7 50       26  
2298             =item truncated_beginning($string)
2299 7         24  
2300 7         38 Adds the locale specific marking to show that the
2301 10         30 string has been truncated at the beginning.
2302 10 100       18  
2303 8 100       48 =cut
2304              
2305             shift->_truncated(initial => @_);
2306 3         13 }
2307              
2308             =item truncated_between($string, $string)
2309              
2310             Adds the locale specific marking to show that something
2311             has been truncated between the two strings. Returns a
2312             string comprising of the concatenation of the first string,
2313             the mark and the second string
2314              
2315             =cut
2316              
2317 1     1 1 1343 shift->_truncated(medial => @_);
2318             }
2319 1         3  
2320 1         7 =item truncated_end($string)
2321 1         4  
2322 1 50       3 Adds the locale specific marking to show that the
2323 1         10 string has been truncated at the end.
2324              
2325 0         0 =cut
2326              
2327             shift->_truncated(final => @_);
2328             }
2329 6     6   21  
2330             =item truncated_word_beginning($string)
2331 6         21  
2332 6         41 Adds the locale specific marking to show that the
2333 6         26 string has been truncated at the beginning. This
2334 6 50       15 should be used in preference to C<truncated_beginning>
2335 6         32 when the truncation occurs on a word boundary.
2336 6         15  
2337 6         40 =cut
2338              
2339             shift->_truncated('word-initial' => @_);
2340             }
2341              
2342             =item truncated_word_between($string, $string)
2343              
2344             Adds the locale specific marking to show that something
2345             has been truncated between the two strings. Returns a
2346             string comprising of the concatenation of the first string,
2347             the mark and the second string. This should be used in
2348             preference to C<truncated_between> when the truncation
2349             occurs on a word boundary.
2350              
2351             =cut
2352              
2353             shift->_truncated('word-medial' => @_);
2354             }
2355              
2356             =item truncated_word_end($string)
2357 1     1 1 1726  
2358             Adds the locale specific marking to show that the
2359             string has been truncated at the end. This should be
2360             used in preference to C<truncated_end> when the
2361             truncation occurs on a word boundary.
2362              
2363             =cut
2364              
2365             shift->_truncated('word-final' => @_);
2366             }
2367              
2368             =back
2369              
2370 1     1 1 7 =head2 Quoting
2371              
2372             =over 4
2373              
2374             =item quote($string)
2375              
2376             Adds the locale's primary quotation marks to the ends of the string.
2377             Also scans the string for paired primary and auxiliary quotation
2378             marks and flips them.
2379              
2380             eg passing C<z “abc” z> to this method for the C<en_GB> locale
2381 1     1 1 5 gives C<“z ‘abc’ z”>
2382              
2383             =cut
2384              
2385             my ($self, $text) = @_;
2386              
2387             my %quote;
2388             my @bundles = $self->_find_bundle('quote_start');
2389             foreach my $bundle (@bundles) {
2390             my $quote = $bundle->quote_start;
2391             next unless defined $quote;
2392             $quote{start} = $quote;
2393             last;
2394 1     1 1 5 }
2395              
2396             @bundles = $self->_find_bundle('quote_end');
2397             foreach my $bundle (@bundles) {
2398             my $quote = $bundle->quote_end;
2399             next unless defined $quote;
2400             $quote{end} = $quote;
2401             last;
2402             }
2403              
2404             @bundles = $self->_find_bundle('alternate_quote_start');
2405             foreach my $bundle (@bundles) {
2406             my $quote = $bundle->alternate_quote_start;
2407             next unless defined $quote;
2408             $quote{alternate_start} = $quote;
2409 1     1 1 5 last;
2410             }
2411              
2412             @bundles = $self->_find_bundle('alternate_quote_end');
2413             foreach my $bundle (@bundles) {
2414             my $quote = $bundle->alternate_quote_end;
2415             next unless defined $quote;
2416             $quote{alternate_end} = $quote;
2417             last;
2418             }
2419              
2420             # Check to see if we need to switch quotes
2421             foreach (qw( start end alternate_start alternate_end)) {
2422 1     1 1 4 $quote{$_} //= '';
2423             }
2424              
2425             my $from = join ' | ', map {quotemeta} @quote{qw( start end alternate_start alternate_end)};
2426             my %to;
2427             @to{@quote{qw( start end alternate_start alternate_end)}}
2428             = @quote{qw( alternate_start alternate_end start end)};
2429              
2430             my $outer = index($text, $quote{start});
2431             my $inner = index($text, $quote{alternate_start});
2432              
2433             if ($inner == -1 || ($outer > -1 && $inner > -1 && $outer < $inner)) {
2434             $text =~ s{ ( $from ) }{ $to{$1} }msxeg;
2435             }
2436              
2437             return "$quote{start}$text$quote{end}";
2438             }
2439              
2440             =back
2441              
2442             =head2 Miscellaneous
2443 3     3 1 2454  
2444             =over 4
2445 3         6  
2446 3         7 =item more_information()
2447 3         20  
2448 3         9 The more information string is one that can be displayed
2449 3 50       9 in an interface to indicate that more information is
2450 3         7 available.
2451 3         5  
2452             =cut
2453              
2454 3         7 my $self = shift;
2455 3         19  
2456 3         8 my @bundles = $self->_find_bundle('more_information');
2457 3 50       8 foreach my $bundle (@bundles) {
2458 3         6 my $info = $bundle->more_information;
2459 3         6 next unless defined $info;
2460             return $info;
2461             }
2462 3         6 return '';
2463 3         17 }
2464 3         9  
2465 3 50       7  
2466 3         6 =item measurement()
2467 3         3  
2468             Returns the measurement type for the locale
2469              
2470 3         6 =cut
2471 3         17  
2472 3         8 my $self = shift;
2473 3 50       6
2474 3         4 my $measurement_data = $self->measurement_system;
2475 3         6 my $region = $self->region_id || '001';
2476            
2477             my $data = $measurement_data->{$region};
2478            
2479 3         5 until (defined $data) {
2480 12   50     20 $region = $self->region_contained_by->{$region};
2481             $data = $measurement_data->{$region};
2482             }
2483 3         7
  12         21  
2484 3         7 return $data;
2485             }
2486 3         12  
2487             =item paper()
2488 3         7  
2489 3         4 Returns the paper type for the locale
2490              
2491 3 50 33     15 =cut
      33        
      66        
2492 3         70  
  6         20  
2493             my $self = shift;
2494            
2495 3         20 my $paper_size = $self->paper_size;
2496             my $region = $self->region_id || '001';
2497            
2498             my $data = $paper_size->{$region};
2499            
2500             until (defined $data) {
2501             $region = $self->region_contained_by->{$region};
2502             $data = $paper_size->{$region};
2503             }
2504            
2505             return $data;
2506             }
2507              
2508             =back
2509              
2510             =head2 Units
2511              
2512             =over 4
2513 1     1 1 4  
2514             =item all_units()
2515 1         4  
2516 1         10 Returns a list of all the unit identifiers for the locale
2517 1         8  
2518 1 50       5 =cut
2519 1         10  
2520             my $self = shift;
2521 0         0 my @bundles = $self->_find_bundle('units');
2522            
2523             my %units;
2524             foreach my $bundle (reverse @bundles) {
2525             %units = %units, $bundle->units;
2526             }
2527            
2528             return keys %units;
2529             }
2530              
2531             =item unit($number, $unit, $width)
2532 1     1 1 953  
2533             Returns the localised string for the given number and unit formatted for the
2534 1         5 required width. The number must not be the localized version of the number.
2535 1   50     20 The returned string will be in the locale's format, including the number.
2536              
2537 1         3 =cut
2538              
2539 1         3 my ($self, $number, $what, $type) = @_;
2540 0         0 $type //= 'long';
2541 0         0
2542             my $plural = $self->plural($number);
2543            
2544 1         10 my @bundles = $self->_find_bundle('units');
2545             my $format;
2546             foreach my $bundle (@bundles) {
2547             if (exists $bundle->units()->{$type}{$what}{$plural}) {
2548             $format = $bundle->units()->{$type}{$what}{$plural};
2549             last;
2550             }
2551            
2552             if (exists $bundle->units()->{$type}{$what}{other}) {
2553             $format = $bundle->units()->{$type}{$what}{other};
2554 1     1 1 3 last;
2555             }
2556 1         5 }
2557 1   50     19
2558             # Check for aliases
2559 1         3 unless ($format) {
2560             my $original_type = $type;
2561 1         3 my @aliases = $self->_find_bundle('unit_alias');
2562 0         0 foreach my $alias (@aliases) {
2563 0         0 $type = $alias->unit_alias()->{$original_type};
2564             next unless $type;
2565             foreach my $bundle (@bundles) {
2566 1         4 if (exists $bundle->units()->{$type}{$what}{$plural}) {
2567             $format = $bundle->units()->{$type}{$what}{$plural};
2568             last;
2569             }
2570            
2571             if (exists $bundle->units()->{$type}{$what}{other}) {
2572             $format = $bundle->units()->{$type}{$what}{other};
2573             last;
2574             }
2575             }
2576             }
2577             $type = $original_type;
2578             }
2579            
2580             # Check for a compound unit that we don't specifically have
2581             if (! $format && (my ($dividend, $divisor) = $what =~ /^(.+)-per-(.+)$/)) {
2582 0     0 1 0 return $self->_unit_compound($number, $dividend, $divisor, $type);
2583 0         0 }
2584            
2585 0         0 $number = $self->format_number($number);
2586 0         0 return $number unless $format;
2587 0         0
2588             $format =~ s/\{0\}/$number/g;
2589            
2590 0         0 return $format;
2591             }
2592              
2593             my ($self, $number, $dividend_what, $divisor_what, $type) = @_;
2594            
2595             $type //= 'long';
2596            
2597             my $dividend = $self->unit($number, $dividend_what, $type);
2598             my $divisor = $self->_unit_per($divisor_what, $type);
2599             if ($divisor) {
2600             my $format = $divisor;
2601             $format =~ s/\{0\}/$dividend/;
2602 738     738 1 2769 return $format;
2603 738   100     1996 }
2604            
2605 738         1928 $divisor = $self->unit(1, $divisor_what, $type);
2606            
2607 738         1540 my $one = $self->format_number(1);
2608 738         3822 $divisor =~ s/\s*$one\s*//;
2609 738         1173
2610 748 100       2572 my @bundles = $self->_find_bundle('units');
2611 728         1340 my $format;
2612 728         850 foreach my $bundle (@bundles) {
2613             if (exists $bundle->units()->{$type}{per}{''}) {
2614             $format = $bundle->units()->{$type}{per}{''};
2615 20 50       51 last;
2616 0         0 }
2617 0         0 }
2618              
2619             # Check for aliases
2620             unless ($format) {
2621             my $original_type = $type;
2622 738 100       1044 my @aliases = $self->_find_bundle('unit_alias');
2623 10         13 foreach my $alias (@aliases) {
2624 10         20 $type = $alias->unit_alias()->{$original_type};
2625 10         55 foreach my $bundle (@bundles) {
2626 10         29 if (exists $bundle->units()->{$type}{per}{1}) {
2627 10 50       24 $format = $bundle->units()->{$type}{per}{1};
2628 10         17 last;
2629 16 100       48 }
2630 4         13 }
2631 4         7 }
2632             }
2633            
2634 12 50       27 $format =~ s/\{0\}/$dividend/g;
2635 0         0 $format =~ s/\{1\}/$divisor/g;
2636 0         0
2637             return $format;
2638             }
2639              
2640 10         15 =item unit_name($unit_identifier)
2641              
2642             This method returns the localised name of the unit
2643              
2644 738 100 66     1405 =cut
2645 6         15  
2646             my ($self, $what) = @_;
2647            
2648 732         1785 my @bundles = $self->_find_bundle('units');
2649 732 50       1494 my $name;
2650             foreach my $bundle (@bundles) {
2651 732         2011 if (exists $bundle->units()->{long}{$what}{name}) {
2652             return $bundle->units()->{long}{$what}{name};
2653 732         3609 }
2654             }
2655            
2656             # Check for aliases
2657 6     6   11 my $type = 'long';
2658             my @aliases = $self->_find_bundle('unit_alias');
2659 6   50     13 foreach my $alias (@aliases) {
2660             $type = $alias->unit_alias()->{$type};
2661 6         35 next unless $type;
2662 6         18 foreach my $bundle (@bundles) {
2663 6 50       10 if (exists $bundle->units()->{$type}{$what}{name}) {
2664 6         10 return $bundle->units()->{$type}{$what}{name};
2665 6         14 }
2666 6         34 }
2667             }
2668            
2669 0         0 return '';
2670             }
2671 0         0  
2672 0         0 my ($self, $what, $type) = @_;
2673            
2674 0         0 my @bundles = $self->_find_bundle('units');
2675 0         0 my $name;
2676 0         0 foreach my $bundle (@bundles) {
2677 0 0       0 if (exists $bundle->units()->{$type}{$what}{per}) {
2678 0         0 return $bundle->units()->{$type}{$what}{per};
2679 0         0 }
2680             }
2681            
2682             # Check for aliases
2683             my @aliases = $self->_find_bundle('unit_alias');
2684 0 0       0 foreach my $alias (@aliases) {
2685 0         0 $type = $alias->unit_alias()->{$type};
2686 0         0 next unless $type;
2687 0         0 foreach my $bundle (@bundles) {
2688 0         0 if (exists $bundle->units()->{$type}{$what}{per}) {
2689 0         0 return $bundle->units()->{$type}{$what}{per};
2690 0 0       0 }
2691 0         0 }
2692 0         0 }
2693            
2694             return '';
2695             }
2696              
2697             my $self = shift;
2698 0         0  
2699 0         0 my @number_symbols_bundles = $self->_find_bundle('number_symbols');
2700             my $symbols_type = $self->default_numbering_system;
2701 0         0
2702             foreach my $bundle (@number_symbols_bundles) {
2703             if (exists $bundle->number_symbols()->{$symbols_type}{alias}) {
2704             $symbols_type = $bundle->number_symbols()->{$symbols_type}{alias};
2705             redo;
2706             }
2707            
2708             return $bundle->number_symbols()->{$symbols_type}{timeSeparator}
2709             if exists $bundle->number_symbols()->{$symbols_type}{timeSeparator};
2710             }
2711 0     0 1 0 return ':';
2712             }
2713 0         0  
2714 0         0 =item duration_unit($format, @data)
2715 0         0  
2716 0 0       0 This method formats a duration. The format must be one of
2717 0         0 C<hm>, C<hms> or C<ms> corresponding to C<hour minute>,
2718             C<hour minute second> and C<minute second> respectively.
2719             The data must correspond to the given format.
2720              
2721             =cut
2722 0         0  
2723 0         0 # data in hh,mm; hh,mm,ss or mm,ss
2724 0         0 my ($self, $format, @data) = @_;
2725 0         0
2726 0 0       0 my $bundle = $self->_find_bundle('duration_units');
2727 0         0 my $parsed = $bundle->duration_units()->{$format};
2728 0 0       0
2729 0         0 my $num_format = '#';
2730             foreach my $entry ( qr/(hh?)/, qr/(mm?)/, qr/(ss?)/) {
2731             $num_format = '00' if $parsed =~ s/$entry/$self->format_number(shift(@data), $num_format)/e;
2732             }
2733            
2734 0         0 my $time_separator = $self->_get_time_separator;
2735            
2736             $parsed =~ s/:/$time_separator/g;
2737            
2738 6     6   9 return $parsed;
2739             }
2740 6         11  
2741 6         31 =back
2742 6         9  
2743 8 100       40 =head2 Yes or No?
2744 4         13  
2745             =over 4
2746              
2747             =item is_yes($string)
2748              
2749 2         4 Returns true if the passed in string matches the locale's
2750 2         12 idea of a string designating yes. Note that under POSIX
2751 2         5 rules unless the locale's word for yes starts with C<Y>
2752 2 50       6 (U+0079) then a single 'y' will also be accepted as yes.
2753 2         5 The string will be matched case insensitive.
2754 2 50       8  
2755 2         7 =cut
2756              
2757             my ($self, $test_str) = @_;
2758            
2759             my $bundle = $self->_find_bundle('yesstr');
2760 0         0 return $test_str =~ $bundle->yesstr ? 1 : 0;
2761             }
2762              
2763             =item is_no($string)
2764 12     12   18  
2765             Returns true if the passed in string matches the locale's
2766 12         22 idea of a string designating no. Note that under POSIX
2767 12         94 rules unless the locale's word for no starts with C<n>
2768             (U+006E) then a single 'n' will also be accepted as no
2769 12         25 The string will be matched case insensitive.
2770 24 50       81  
2771 0         0 =cut
2772 0         0  
2773             my ($self, $test_str) = @_;
2774            
2775             my $bundle = $self->_find_bundle('nostr');
2776 24 100       69 return $test_str =~ $bundle->nostr ? 1 : 0;
2777             }
2778 0         0  
2779             =back
2780              
2781             =cut
2782              
2783             =head2 Transliteration
2784              
2785             This method requires Perl version 5.18 or above to use and for you to have
2786             installed the optional C<Bundle::CLDR::Transformations>
2787              
2788             =over 4
2789              
2790             =item transform(from => $from, to => $to, variant => $variant, text => $text)
2791              
2792 3     3 1 8 This method returns the transliterated string of C<text> from script C<from>
2793             to script C<to> using variant C<variant>. If C<from> is not given then the
2794 3         7 current locale's script is used. If C<text> is not given then it defaults to an
2795 3         22 empty string. The C<variant> is optional.
2796              
2797 3         4 =cut
2798 3         13  
2799 9 100       48 _new_perl();
  7         23  
2800            
2801             my ($self, %params) = @_;
2802 3         12
2803             my $from = $params{from} // $self;
2804 3         10 my $to = $params{to};
2805             my $variant = $params{variant} // 'Any';
2806 3         17 my $text = $params{text} // '';
2807            
2808             ($from, $to) = map {ref $_ ? $_->likely_subtag->script_id() : $_} ($from, $to);
2809             $_ = ucfirst(lc $_) foreach ($from, $to, $variant);
2810            
2811             my $package = __PACKAGE__ . "::Transformations::${variant}::${from}::${to}";
2812             my ($canload, $error) = Class::Load::try_load_class($package, { -version => $VERSION});
2813             if ($canload) {
2814             Class::Load::load_class($package, { -version => $VERSION});
2815             }
2816             else {
2817             warn $error;
2818             return $text; # Can't load transform module so return original text
2819             }
2820             use feature 'state';
2821             state $transforms;
2822             $transforms->{$variant}{$from}{$to} //= $package->new();
2823             my $rules = $transforms->{$variant}{$from}{$to}->transforms();
2824            
2825             # First get the filter rule
2826 2     2 1 8 my $filter = $rules->[0];
2827            
2828 2         7 # Break up the input on the filter
2829 2 100       72 my @text;
2830             pos($text) = 0;
2831             while (pos($text) < length($text)) {
2832             my $characters = '';
2833             while (my ($char) = $text =~ /($filter)/) {
2834             $characters .= $char;
2835             pos($text) = pos($text) + length $char;
2836             }
2837             push @text, $characters;
2838             last unless pos($text) < length $text;
2839            
2840             $characters = '';
2841             while ($text !~ /$filter/) {
2842             my ($char) = $text =~ /\G(\X)/;
2843 2     2 1 9 $characters .= $char;
2844             pos($text) = pos($text) + length $char;
2845 2         6 }
2846 2 100       40 push @text, $characters;
2847             }
2848            
2849             my $to_transform = 1;
2850            
2851             foreach my $characters (@text) {
2852             if ($to_transform) {
2853             foreach my $rule (@$rules[1 .. @$rules -1 ]) {
2854             if ($rule->{type} eq 'transform') {
2855             $characters = $self->_transformation_transform($characters, $rule->{data}, $variant);
2856             }
2857             else {
2858             $characters = $self->_transform_convert($characters, $rule->{data});
2859             }
2860             }
2861             }
2862             $to_transform = ! $to_transform;
2863             }
2864            
2865             return join '', @text;
2866             }
2867              
2868             my ($self, $text, $rules, $variant) = @_;
2869            
2870 0     0 1 0 foreach my $rule (@$rules) {
2871             for (lc $rule->{to}) {
2872 0         0 if ($_ eq 'nfc') {
2873             $text = Unicode::Normalize::NFC($text);
2874 0   0     0 }
2875 0         0 elsif($_ eq 'nfd') {
2876 0   0     0 $text = Unicode::Normalize::NFD($text);
2877 0   0     0 }
2878             elsif($_ eq 'nfkd') {
2879 0 0       0 $text = Unicode::Normalize::NFKD($text);
  0         0  
2880 0         0 }
2881             elsif($_ eq 'nfkc') {
2882 0         0 $text = Unicode::Normalize::NFKC($text);
2883 0         0 }
2884 0 0       0 elsif($_ eq 'lower') {
2885 0         0 $text = lc($text);
2886             }
2887             elsif($_ eq 'upper') {
2888 0         0 $text = uc($text);
2889 0         0 }
2890             elsif($_ eq 'title') {
2891 21     21   248 $text =~ s/(\X)/\u$1/g;
  21         42  
  21         164985  
2892 0         0 }
2893 0   0     0 elsif($_ eq 'null') {
2894 0         0 }
2895             elsif($_ eq 'remove') {
2896             $text = '';
2897 0         0 }
2898             else {
2899             $text = $self->transform(text => $text, variant => $variant, from => $rule->{from}, to => $rule->{to});
2900 0         0 }
2901 0         0 }
2902 0         0 }
2903 0         0 return $text;
2904 0         0 }
2905 0         0  
2906 0         0 my ($self, $text, $rules) = @_;
2907            
2908 0         0 pos($text) = 0; # Make sure we start scanning at the beginning of the text
2909 0 0       0
2910             CHARACTER: while (pos($text) < length($text)) {
2911 0         0 foreach my $rule (@$rules) {
2912 0         0 next if length $rule->{before} && $text !~ /$rule->{before}\G/;
2913 0         0 my $regex = $rule->{replace};
2914 0         0 $regex .= '(' . $rule->{after} . ')' if length $rule->{after};
2915 0         0 my $result = 'q(' . $rule->{result} . ')';
2916             $result .= '. $1' if length $rule->{after};
2917 0         0 if ($text =~ s/\G$regex/eval $result/e) {
2918             pos($text) += length($rule->{result}) - $rule->{revisit};
2919             next CHARACTER;
2920 0         0 }
2921             }
2922 0         0
2923 0 0       0 pos($text)++;
2924 0         0 }
2925 0 0       0
2926 0         0 return $text;
2927             }
2928              
2929 0         0 =back
2930              
2931             =head2 Lists
2932              
2933 0         0 =over 4
2934              
2935             =item list(@data)
2936 0         0  
2937             Returns C<data> as a string formatted by the locales idea of producing a list
2938             of elements. What is returned can be effected by the locale and the number
2939             of items in C<data>. Note that C<data> can contain 0 or more items.
2940 0     0   0  
2941             =cut
2942 0         0  
2943 0         0 my ($self, @data) = @_;
2944 0 0       0
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2945 0         0 # Short circuit on 0 or 1 entries
2946             return '' unless @data;
2947             return $data[0] if 1 == @data;
2948 0         0
2949             my @bundles = $self->_find_bundle('listPatterns');
2950            
2951 0         0 my %list_data;
2952             foreach my $bundle (reverse @bundles) {
2953             my %listPatterns = %{$bundle->listPatterns};
2954 0         0 @list_data{keys %listPatterns} = values %listPatterns;
2955             }
2956            
2957 0         0 if (my $pattern = $list_data{scalar @data}) {
2958             $pattern=~s/\{([0-9]+)\}/$data[$1]/eg;
2959             return $pattern;
2960 0         0 }
2961            
2962             my ($start, $middle, $end) = @list_data{qw( start middle end )};
2963 0         0
2964             # First do the end
2965             my $pattern = $end;
2966             $pattern=~s/\{1\}/pop @data/e;
2967             $pattern=~s/\{0\}/pop @data/e;
2968 0         0
2969             # If there is any data left do the middle
2970             while (@data > 1) {
2971 0         0 my $current = $pattern;
2972             $pattern = $middle;
2973             $pattern=~s/\{1\}/$current/;
2974             $pattern=~s/\{0\}/pop @data/e;
2975 0         0 }
2976            
2977             # Now do the start
2978             my $current = $pattern;
2979 0     0   0 $pattern = $start;
2980             $pattern=~s/\{1\}/$current/;
2981 0         0 $pattern=~s/\{0\}/pop @data/e;
2982            
2983 0         0 return $pattern;
2984 0         0 }
2985 0 0 0     0  
2986 0         0 =back
2987 0 0       0  
2988 0         0 =head2 Pluralisation
2989 0 0       0  
2990 0 0       0 =over 4
  0         0  
2991 0         0  
2992 0         0 =item plural($number)
2993              
2994             This method takes a number and uses the locale's pluralisation
2995             rules to calculate the type of pluralisation required for
2996 0         0 units, currencies and other data that changes depending on
2997             the plural state of the number
2998              
2999 0         0 =item plural_range($start, $end)
3000              
3001             This method returns the plural type for the range $start to $end
3002             $start and $end can either be numbers or one of the plural types
3003             C<zero one two few many other>
3004              
3005             =cut
3006              
3007             my $self = shift;
3008              
3009             foreach my $property (qw(
3010             month_format_wide month_format_abbreviated month_format_narrow
3011             month_stand_alone_wide month_stand_alone_abbreviated
3012             month_stand_alone_narrow day_format_wide day_format_abbreviated
3013             day_format_narrow day_stand_alone_wide day_stand_alone_abreviated
3014             day_stand_alone_narrow quater_format_wide quater_format_abbreviated
3015             quater_format_narrow quater_stand_alone_wide
3016             quater_stand_alone_abreviated quater_stand_alone_narrow
3017 5     5 1 1096 am_pm_wide am_pm_abbreviated am_pm_narrow am_pm_format_wide
3018             am_pm_format_abbreviated am_pm_format_narrow am_pm_stand_alone_wide
3019             am_pm_stand_alone_abbreviated am_pm_stand_alone_narrow era_wide
3020 5 100       18 era_abbreviated era_narrow date_format_full date_format_long date_format_medium
3021 4 100       16 date_format_short time_format_full
3022             time_format_long time_format_medium time_format_short
3023 3         11 datetime_format_full datetime_format_long
3024             datetime_format_medium datetime_format_short
3025 3         18 available_formats format_data
3026 3         5 )) {
3027 6         5 my $method = "_clear_$property";
  6         28  
3028 6         21 $self->$method;
3029             }
3030             }
3031 3 100       11  
3032 1         7 my ($self, $type, $width) = @_;
  2         7  
3033 1         10 my $default_calendar = $self->default_calendar();
3034             my @bundles = $self->_find_bundle('calendar_months');
3035             BUNDLES: {
3036 2         6 foreach my $bundle (@bundles) {
3037             my $months = $bundle->calendar_months;
3038             if (exists $months->{$default_calendar}{alias}) {
3039 2         4 $default_calendar = $months->{$default_calendar}{alias};
3040 2         6 redo BUNDLES;
  2         6  
3041 2         5 }
  2         5  
3042              
3043             if (exists $months->{$default_calendar}{$type}{$width}{alias}) {
3044 2         6 ($type, $width) = @{$months->{$default_calendar}{$type}{$width}{alias}}{qw(context type)};
3045 1         2 redo BUNDLES;
3046 1         1 }
3047 1         4
3048 1         3 my $result = $months->{$default_calendar}{$type}{$width}{nonleap};
  1         2  
3049             return $result if defined $result;
3050             }
3051             if ($default_calendar ne 'gregorian') {
3052 2         4 $default_calendar = 'gregorian';
3053 2         3 redo BUNDLES;
3054 2         5 }
3055 2         5 }
  2         4  
3056             return [];
3057 2         10 }
3058              
3059             my $self = shift;
3060             my ($type, $width) = (qw(format wide));
3061            
3062             return $self->_build_any_month($type, $width);
3063             }
3064              
3065             my $self = shift;
3066             my ($type, $width) = (qw(format abbreviated));
3067            
3068             return $self->_build_any_month($type, $width);
3069             }
3070              
3071             my $self = shift;
3072             my ($type, $width) = (qw(format narrow));
3073            
3074             return $self->_build_any_month($type, $width);
3075             }
3076              
3077             my $self = shift;
3078             my ($type, $width) = ('stand-alone', 'wide');
3079            
3080             return $self->_build_any_month($type, $width);
3081             }
3082 0     0   0  
3083             my $self = shift;
3084 0         0 my ($type, $width) = ('stand-alone', 'abbreviated');
3085            
3086             return $self->_build_any_month($type, $width);
3087             }
3088              
3089             my $self = shift;
3090             my ($type, $width) = ('stand-alone', 'narrow');
3091            
3092             return $self->_build_any_month($type, $width);
3093             }
3094              
3095             my ($self, $type, $width) = @_;
3096            
3097             my $default_calendar = $self->default_calendar();
3098              
3099             my @bundles = $self->_find_bundle('calendar_days');
3100             BUNDLES: {
3101             foreach my $bundle (@bundles) {
3102 0         0 my $days= $bundle->calendar_days;
3103 0         0
3104             if (exists $days->{$default_calendar}{alias}) {
3105             $default_calendar = $days->{$default_calendar}{alias};
3106             redo BUNDLES;
3107             }
3108 8     8   30  
3109 8         27 if (exists $days->{$default_calendar}{$type}{$width}{alias}) {
3110 8         25 ($type, $width) = @{$days->{$default_calendar}{$type}{$width}{alias}}{qw(context type)};
3111             redo BUNDLES;
3112 8         66 }
  12         19  
3113 16         34 my $result = $days->{$default_calendar}{$type}{$width};
3114 16 50       44 return [ @{$result}{qw( mon tue wed thu fri sat sun )} ] if keys %$result;
3115 0         0 }
3116 0         0 if ($default_calendar ne 'gregorian') {
3117             $default_calendar = 'gregorian';
3118             redo BUNDLES;
3119 16 100       42 }
3120 4         7 }
  4         12  
3121 4         11  
3122             return [];
3123             }
3124 12         19  
3125 12 100       119 my $self = shift;
3126             my ($type, $width) = (qw(format wide));
3127 0 0       0
3128 0         0 return $self->_build_any_day($type, $width);
3129 0         0 }
3130              
3131             my $self = shift;
3132 0         0 my ($type, $width) = (qw(format abbreviated));
3133            
3134             return $self->_build_any_day($type, $width);
3135             }
3136 2     2   1114  
3137 2         7 my $self = shift;
3138             my ($type, $width) = (qw(format narrow));
3139 2         9
3140             return $self->_build_any_day($type, $width);
3141             }
3142              
3143 1     1   1039 my $self = shift;
3144 1         3 my ($type, $width) = ('stand-alone', 'wide');
3145            
3146 1         3 return $self->_build_any_day($type, $width);
3147             }
3148              
3149             my $self = shift;
3150 1     1   627 my ($type, $width) = ('stand-alone', 'abbreviated');
3151 1         4  
3152             return $self->_build_any_day($type, $width);
3153 1         3 }
3154              
3155             my $self = shift;
3156             my ($type, $width) = ('stand-alone', 'narrow');
3157 1     1   689
3158 1         3 return $self->_build_any_day($type, $width);
3159             }
3160 1         3  
3161             my ($self, $type, $width) = @_;
3162            
3163             my $default_calendar = $self->default_calendar();
3164 2     2   646  
3165 2         6 my @bundles = $self->_find_bundle('calendar_quarters');
3166             BUNDLES: {
3167 2         7 foreach my $bundle (@bundles) {
3168             my $quarters= $bundle->calendar_quarters;
3169            
3170             if (exists $quarters->{$default_calendar}{alias}) {
3171 1     1   618 $default_calendar = $quarters->{$default_calendar}{alias};
3172 1         3 redo BUNDLES;
3173             }
3174 1         4  
3175             if (exists $quarters->{$default_calendar}{$type}{$width}{alias}) {
3176             ($type, $width) = @{$quarters->{$default_calendar}{$type}{$width}{alias}}{qw(context type)};
3177             redo BUNDLES;
3178 7     7   14 }
3179            
3180 7         22 my $result = $quarters->{$default_calendar}{$type}{$width};
3181             return [ @{$result}{qw( 0 1 2 3 )} ] if keys %$result;
3182 7         20 }
3183             if ($default_calendar ne 'gregorian') {
3184 7         42 $default_calendar = 'gregorian';
  10         16  
3185 13         30 redo BUNDLES;
3186             }
3187 13 50       31 }
3188 0         0  
3189 0         0 return [];
3190             }
3191              
3192 13 100       34 my $self = shift;
3193 3         5 my ($type, $width) = (qw( format wide ));
  3         9  
3194 3         16
3195             return $self->_build_any_quarter($type, $width);
3196 10         13 }
3197 10 100       27  
  7         113  
3198             my $self = shift;
3199 0 0       0 my ($type, $width) = (qw(format abbreviated));
3200 0         0  
3201 0         0 return $self->_build_any_quarter($type, $width);
3202             }
3203              
3204             my $self = shift;
3205 0         0 my ($type, $width) = (qw(format narrow));
3206              
3207             return $self->_build_any_quarter($type, $width);
3208             }
3209 2     2   824  
3210 2         8 my $self = shift;
3211             my ($type, $width) = ('stand-alone', 'wide');
3212 2         10  
3213             return $self->_build_any_quarter($type, $width);
3214             }
3215              
3216 1     1   910 my $self = shift;
3217 1         14 my ($type, $width) = ('stand-alone', 'abbreviated');
3218            
3219 1         4 return $self->_build_any_quarter($type, $width);
3220             }
3221              
3222             my $self = shift;
3223 1     1   600 my ($type, $width) = ('stand-alone', 'narrow');
3224 1         3  
3225             return $self->_build_any_quarter($type, $width);
3226 1         4 }
3227              
3228             # Time in hhmm
3229             my ($self, $time, $type) = @_;
3230 1     1   652 $type //= 'default';
3231 1         2
3232             my $default_calendar = $self->default_calendar();
3233 1         4
3234             my $bundle = $self->_find_bundle('day_period_data');
3235            
3236             my $day_period = $bundle->day_period_data;
3237 1     1   612 $day_period = $self->$day_period($default_calendar, $time, $type);
3238 1         4
3239             # The day period for root is commented out but I need that data so will
3240 1         3 # fix up here as a default
3241             $day_period ||= $time < 1200 ? 'am' : 'pm';
3242            
3243             my $am_pm = $self->am_pm_format_abbreviated;
3244 1     1   635
3245 1         4 return $am_pm->{$day_period};
3246             }
3247 1         3  
3248             my ($self, $type, $width) = @_;
3249              
3250             my $default_calendar = $self->default_calendar();
3251 6     6   14 my @result;
3252             my @bundles = $self->_find_bundle('day_periods');
3253 6         20 my %return;
3254              
3255 6         14 BUNDLES: {
3256             foreach my $bundle (@bundles) {
3257 6         38 my $am_pm = $bundle->day_periods;
  9         15  
3258 12         29
3259             if (exists $am_pm->{$default_calendar}{alias}) {
3260 12 50       28 $default_calendar = $am_pm->{$default_calendar}{alias};
3261 0         0 redo BUNDLES;
3262 0         0 }
3263              
3264             if (exists $am_pm->{$default_calendar}{$type}{alias}) {
3265 12 100       29 $type = $am_pm->{$default_calendar}{$type}{alias};
3266 3         4 redo BUNDLES;
  3         10  
3267 3         8 }
3268            
3269             if (exists $am_pm->{$default_calendar}{$type}{$width}{alias}) {
3270 9         17 my $original_width = $width;
3271 9 100       31 $width = $am_pm->{$default_calendar}{$type}{$width}{alias}{width};
  6         96  
3272             $type = $am_pm->{$default_calendar}{$type}{$original_width}{alias}{context};
3273 0 0       0 redo BUNDLES;
3274 0         0 }
3275 0         0
3276             my $result = $am_pm->{$default_calendar}{$type}{$width};
3277            
3278             foreach (keys %$result) {
3279 0         0 $return{$_} = $result->{$_} unless exists $return{$_};
3280             }
3281             }
3282             }
3283 1     1   583  
3284 1         3 return \%return;
3285             }
3286 1         5  
3287             # The first 3 are to link in with Date::Time::Locale
3288             my $self = shift;
3289             my ($type, $width) = (qw( format wide ));
3290 1     1   919
3291 1         4 my $result = $self->_build_any_am_pm($type, $width);
3292            
3293 1         5 return [ @$result{qw( am pm )} ];
3294             }
3295              
3296             my $self = shift;
3297 1     1   703 my ($type, $width) = (qw( format abbreviated ));
3298 1         3  
3299             my $result = $self->_build_any_am_pm($type, $width);
3300 1         4
3301             return [ @$result{qw( am pm )} ];
3302             }
3303              
3304 1     1   668 my $self = shift;
3305 1         3 my ($type, $width) = (qw( format narrow ));
3306            
3307 1         4 my $result = $self->_build_any_am_pm($type, $width);
3308            
3309             return [ @$result{qw( am pm )} ];
3310             }
3311 1     1   624  
3312 1         2 # Now we do the full set of data
3313             my $self = shift;
3314 1         4 my ($type, $width) = (qw( format wide ));
3315            
3316             return $self->_build_any_am_pm($type, $width);
3317             }
3318 1     1   693  
3319 1         3 my $self = shift;
3320             my ($type, $width) = (qw( format abbreviated ));
3321 1         5  
3322             return $self->_build_any_am_pm($type, $width);
3323             }
3324              
3325             my $self = shift;
3326 3     3 1 1470 my ($type, $width) = (qw( format narrow ));
3327 3   50     17
3328             return $self->_build_any_am_pm($type, $width);
3329 3         11 }
3330              
3331 3         8 my $self = shift;
3332             my ($type, $width) = ('stand-alone', 'wide');
3333 3         52
3334 3         74 return $self->_build_any_am_pm($type, $width);
3335             }
3336              
3337             my $self = shift;
3338 3 0 33     7 my ($type, $width) = ('stand-alone', 'abbreviated');
3339              
3340 3         42 return $self->_build_any_am_pm($type, $width);
3341             }
3342 3         25  
3343             my $self = shift;
3344             my ($type, $width) = ('stand-alone', 'narrow');
3345            
3346 10     10   20 return $self->_build_any_am_pm($type, $width);
3347             }
3348 10         27  
3349 10         17 my ($self, $width) = @_;
3350 10         22  
3351 10         59 my $default_calendar = $self->default_calendar();
3352             my @bundles = $self->_find_bundle('eras');
3353             BUNDLES: {
3354 10         12 foreach my $bundle (@bundles) {
  19         26  
3355 38         56 my $eras = $bundle->eras;
3356            
3357 38 50       69 if (exists $eras->{$default_calendar}{alias}) {
3358 0         0 $default_calendar = $eras->{$default_calendar}{alias};
3359 0         0 redo BUNDLES;
3360             }
3361              
3362 38 50       61 if (exists $eras->{$default_calendar}{$width}{alias}) {
3363 0         0 $width = $eras->{$default_calendar}{$width}{alias};
3364 0         0 redo BUNDLES;
3365             }
3366            
3367 38 100       67 my $result = $eras->{$default_calendar}{$width};
3368 9         11
3369 9         19 my @result;
3370 9         12 @result[keys %$result] = values %$result;
3371 9         13
3372             return \@result if keys %$result;
3373             }
3374 29         33 if ($default_calendar ne 'gregorian') {
3375             $default_calendar = 'gregorian';
3376 29         64 redo BUNDLES;
3377 164 100       272 }
3378             }
3379              
3380             return [];
3381             }
3382 10         89
3383             # The next three are for DateDime::Locale
3384             my $self = shift;
3385             my ($width) = (qw( wide ));
3386              
3387 1     1   601 my $result = $self->_build_any_era($width);
3388 1         2
3389             return [@$result[0, 1]];
3390 1         4 }
3391              
3392 1         20 my $self = shift;
3393             my ($width) = (qw( abbreviated ));
3394              
3395             my $result = $self->_build_any_era($width);
3396 2     2   1392
3397 2         6 return [@$result[0, 1]];
3398             }
3399 2         9  
3400             my $self = shift;
3401 2         35 my ($width) = (qw( narrow ));
3402              
3403             my $result = $self->_build_any_era($width);
3404            
3405 1     1   582 return [@$result[0, 1]];
3406 1         3 }
3407              
3408 1         3 # Now get all the era data
3409             my $self = shift;
3410 1         17 my ($width) = (qw( wide ));
3411              
3412             return $self->_build_any_era($width);
3413             }
3414              
3415 1     1   543 my $self = shift;
3416 1         4 my ($width) = (qw( abbreviated ));
3417              
3418 1         3 return $self->_build_any_era($width);
3419             }
3420              
3421             my $self = shift;
3422 1     1   600 my ($type, $width) = (qw( narrow ));
3423 1         3  
3424             return $self->_build_any_era($type, $width);
3425 1         3 }
3426              
3427             *_build_era_stand_alone_wide = \&_build_era_format_wide;
3428             *_build_era_stand_alone_abbreviated = \&_build_era_format_abbreviated;
3429 1     1   612 *_build_era_stand_alone_narrow = \&_build_era_format_narrow;
3430 1         3  
3431             my ($self, $width) = @_;
3432 1         3 my $default_calendar = $self->default_calendar();
3433            
3434             my @bundles = $self->_find_bundle('date_formats');
3435              
3436 1     1   609 BUNDLES: {
3437 1         3 foreach my $bundle (@bundles) {
3438             my $date_formats = $bundle->date_formats;
3439 1         5 if (exists $date_formats->{alias}) {
3440             $default_calendar = $date_formats->{alias};
3441             redo BUNDLES;
3442             }
3443 1     1   658
3444 1         3 my $result = $date_formats->{$default_calendar}{$width};
3445             return $result if $result;
3446 1         4 }
3447             if ($default_calendar ne 'gregorian') {
3448             $default_calendar = 'gregorian';
3449             redo BUNDLES;
3450 1     1   600 }
3451 1         3 }
3452            
3453 1         4 return '';
3454             }
3455              
3456             my $self = shift;
3457 9     9   14
3458             my ($width) = ('full');
3459 9         36 return $self->_build_any_date_format($width);
3460 9         21 }
3461              
3462 9         49 my $self = shift;
  9         11  
3463 9         21
3464             my ($width) = ('long');
3465 9 50       32 return $self->_build_any_date_format($width);
3466 0         0 }
3467 0         0  
3468             my $self = shift;
3469            
3470 9 50       21 my ($width) = ('medium');
3471 0         0 return $self->_build_any_date_format($width);
3472 0         0 }
3473              
3474             my $self = shift;
3475 9         11
3476             my ($width) = ('short');
3477 9         13 return $self->_build_any_date_format($width);
3478 9         34 }
3479              
3480 9 50       95 my ($self, $width) = @_;
3481             my $default_calendar = $self->default_calendar();
3482 0 0       0
3483 0         0 my @bundles = $self->_find_bundle('time_formats');
3484 0         0  
3485             BUNDLES: {
3486             foreach my $bundle (@bundles) {
3487             my $time_formats = $bundle->time_formats;
3488 0         0 if (exists $time_formats->{$default_calendar}{alias}) {
3489             $default_calendar = $time_formats->{$default_calendar}{alias};
3490             redo BUNDLES;
3491             }
3492            
3493 1     1   628 my $result = $time_formats->{$default_calendar}{$width};
3494 1         2 if ($result) {
3495             my $time_separator = $self->_get_time_separator;
3496 1         3 $result =~ s/:/$time_separator/g;
3497             return $result;
3498 1         16 }
3499             }
3500             if ($default_calendar ne 'gregorian') {
3501             $default_calendar = 'gregorian';
3502 1     1   926 redo BUNDLES;
3503 1         2 }
3504             }
3505 1         4 return '';
3506             }
3507 1         14  
3508             my $self = shift;
3509             my $width = 'full';
3510            
3511 1     1   840 return $self->_build_any_time_format($width);
3512 1         4 }
3513              
3514 1         3 my $self = shift;
3515            
3516 1         14 my $width = 'long';
3517             return $self->_build_any_time_format($width);
3518             }
3519              
3520             my $self = shift;
3521 2     2   1126
3522 2         5 my $width = 'medium';
3523             return $self->_build_any_time_format($width);
3524 2         7 }
3525              
3526             my $self = shift;
3527            
3528 2     2   1171 my $width = 'short';
3529 2         4 return $self->_build_any_time_format($width);
3530             }
3531 2         7  
3532             my ($self, $width) = @_;
3533             my $default_calendar = $self->default_calendar();
3534            
3535 2     2   1125 my @bundles = $self->_find_bundle('datetime_formats');
3536 2         4  
3537             BUNDLES: {
3538 2         8 foreach my $bundle (@bundles) {
3539             my $datetime_formats = $bundle->datetime_formats;
3540             if (exists $datetime_formats->{$default_calendar}{alias}) {
3541             $default_calendar = $datetime_formats->{$default_calendar}{alias};
3542             redo BUNDLES;
3543             }
3544            
3545             my $result = $datetime_formats->{$default_calendar}{$width};
3546 9     9   16 return $result if $result;
3547 9         29 }
3548             if ($default_calendar ne 'gregorian') {
3549 9         24 $default_calendar = 'gregorian';
3550             redo BUNDLES;
3551             }
3552 9         51 }
  9         49  
3553 9         26
3554 9 50       27 return '';
3555 0         0 }
3556 0         0  
3557             my $self = shift;
3558            
3559 9         67 my $width = 'full';
3560 9 50       78 my $format = $self->_build_any_datetime_format($width);
3561            
3562 0 0       0 my $date = $self->_build_any_date_format($width);
3563 0         0 my $time = $self->_build_any_time_format($width);
3564 0         0
3565             $format =~ s/\{0\}/$time/;
3566             $format =~ s/\{1\}/$date/;
3567            
3568 0         0 return $format;
3569             }
3570              
3571             my $self = shift;
3572 1     1   24
3573             my $width = 'long';
3574 1         2 my $format = $self->_build_any_datetime_format($width);
3575 1         4
3576             my $date = $self->_build_any_date_format($width);
3577             my $time = $self->_build_any_time_format($width);
3578            
3579 1     1   964 $format =~ s/\{0\}/$time/;
3580             $format =~ s/\{1\}/$date/;
3581 1         3
3582 1         4 return $format;
3583             }
3584              
3585             my $self = shift;
3586 1     1   603
3587             my $width = 'medium';
3588 1         3 my $format = $self->_build_any_datetime_format($width);
3589 1         2
3590             my $date = $self->_build_any_date_format($width);
3591             my $time = $self->_build_any_time_format($width);
3592            
3593 1     1   641 $format =~ s/\{0\}/$time/;
3594             $format =~ s/\{1\}/$date/;
3595 1         3
3596 1         3 return $format;
3597             }
3598              
3599             my $self = shift;
3600 9     9   17
3601 9         24 my $width = 'short';
3602             my $format = $self->_build_any_datetime_format($width);
3603 9         21
3604             my $date = $self->_build_any_date_format($width);
3605             my $time = $self->_build_any_time_format($width);
3606 9         49
  9         18  
3607 9         24 $format =~ s/\{0\}/$time/;
3608 9 50       32 $format =~ s/\{1\}/$date/;
3609 0         0
3610 0         0 return $format;
3611             }
3612              
3613 9         19 my $self = shift;
3614 9 50       19 my $default_calendar = $self->default_calendar();
3615 9         26  
3616 9         31 my @bundles = $self->_find_bundle('datetime_formats_available_formats');
3617 9         71 foreach my $calendar ($default_calendar, 'gregorian') {
3618             foreach my $bundle (@bundles) {
3619             my $datetime_formats_available_formats = $bundle->datetime_formats_available_formats;
3620 0 0       0 my $result = $datetime_formats_available_formats->{$calendar};
3621 0         0 return $result if $result;
3622 0         0 }
3623             }
3624              
3625 0         0 return {};
3626             }
3627              
3628             my ($self, $format) = @_;
3629 1     1   628  
3630 1         3 my $format_data = $self->format_data;
3631              
3632 1         3 return $format_data->{$format} // '';
3633             }
3634              
3635             my $self = shift;
3636 1     1   978  
3637             my $format_data = $self->format_data;
3638 1         2  
3639 1         3 return [keys %$format_data];
3640             }
3641              
3642             my $self = shift;
3643 1     1   630
3644             my $default_calendar = $self->default_calendar();
3645 1         2  
3646 1         3 my @bundles = $self->_find_bundle('date_formats');
3647             foreach my $calendar ($default_calendar, 'gregorian') {
3648             foreach my $bundle (@bundles) {
3649             my $date_formats = $bundle->date_formats;
3650 1     1   661 my $result = $date_formats->{$calendar}{default};
3651             return $result if $result;
3652 1         2 }
3653 1         3 }
3654             }
3655              
3656             my $self = shift;
3657 5     5   13
3658 5         14 my $default_calendar = $self->default_calendar();
3659              
3660 5         14 my @bundles = $self->_find_bundle('time_formats');
3661             foreach my $calendar ($default_calendar, 'gregorian') {
3662             foreach my $bundle (@bundles) {
3663 5         32 my $time_formats = $bundle->time_formats;
  5         9  
3664 5         19 my $result = $time_formats->{$calendar}{default};
3665 5 50       18 return $result if $result;
3666 0         0 }
3667 0         0 }
3668             }
3669              
3670 5         14 my $self = shift;
3671 5 50       14  
3672             return $self->time_format_short() =~ /h|K/ ? 0 : 1;
3673 0 0       0 }
3674 0         0  
3675 0         0 {
3676             my %days_2_number = (
3677             mon => 1,
3678             tue => 2,
3679 0         0 wen => 3,
3680             thu => 4,
3681             fri => 5,
3682             sat => 6,
3683 2     2   11690 sun => 7,
3684             );
3685 2         5  
3686 2         7  
3687             my $self = shift;
3688 2         10  
3689 2         10 my $first_day = $self->week_data_first_day;
3690            
3691 2         8 return $days_2_number{$first_day};
3692 2         8 }
3693             }
3694 2         31  
3695             # Sub to mangle Unicode regex to Perl regex
3696             # Backwards compatibility hack
3697             *_unicode_to_perl = eval <<'EOT' || \&_new_perl;
3698 1     1   979 sub {
3699             my $regex = shift;
3700 1         3  
3701 1         3 return '' unless length $regex;
3702             $regex =~ s/
3703 1         4 (?:\\\\)*+ # Pairs of \
3704 1         5 (?!\\) # Not followed by \
3705             \K # But we don't want to keep that
3706 1         3 (?<set> # Capture this
3707 1         4 \[ # Start a set
3708             (?:
3709 1         13 [^\[\]\\]+ # One or more of not []\
3710             | # or
3711             (?:
3712             (?:\\\\)*+ # One or more pairs of \ without back tracking
3713 1     1   637 \\. # Followed by an escaped character
3714             )
3715 1         3 | # or
3716 1         3 (?&set) # An inner set
3717             )++ # Do the inside set stuff one or more times without backtracking
3718 1         3 \] # End the set
3719 1         4 )
3720             / _convert($1) /xeg;
3721 1         3 no warnings "experimental::regex_sets";
3722 1         3 no warnings "deprecated"; # Because CLDR uses surrogates
3723             return qr/$regex/x;
3724 1         13 };
3725              
3726             EOT
3727              
3728 1     1   706 # Backwards compatibility hack
3729             *_convert = eval <<'EOT' || \&_new_perl;
3730 1         3 sub {
3731 1         3 my $set = shift;
3732            
3733 1         3 # Some definitions
3734 1         4 my $posix = qr/(?(DEFINE)
3735             (?<posix> (?> \[: .+? :\] ) )
3736 1         4 )/x;
3737 1         3
3738             # Convert Unicode escapes \u1234 to characters
3739 1         14 $set =~ s/\\u(\p{Ahex}+)/chr(hex($1))/egx;
3740            
3741             # Check to see if this is a normal character set
3742             my $normal = 0;
3743 0     0   0
3744 0         0 $normal = 1 if $set =~ /^
3745             \s* # Possible white space
3746 0         0 \[ # Opening set
3747 0         0 ^? # Possible negation
3748 0         0 (?: # One of
3749 0         0 [^\[\]]++ # Not an open or close set
3750 0         0 | # Or
3751 0 0       0 (?<=\\)[\[\]] # An open or close set preceded by \
3752             | # Or
3753             (?:
3754             \s* # Possible white space
3755 0         0 (?&posix) # A posix class
3756             (?! # Not followed by
3757             \s* # Possible white space
3758             [&-] # A Unicode regex op
3759 0     0 1 0 \s* # Possible white space
3760             \[ # A set opener
3761 0         0 )
3762             )
3763 0   0     0 )+
3764             \] # Close the set
3765             \s* # Possible white space
3766             $
3767 0     0   0 $posix
3768             /x;
3769 0         0
3770             # Convert posix to perl
3771 0         0 $set =~ s/\[:(.*?):\]/\\p{$1}/g;
3772            
3773             if ($normal) {
3774             return "$set";
3775 0     0   0 }
3776            
3777 0         0 return Unicode::Regex::Set::parse($set);
3778             }
3779 0         0  
3780 0         0 EOT
3781 0         0  
3782 0         0 # The following pod is for methods defined in the Moo Role
3783 0         0 # files that are automatically generated from the data
3784 0 0       0 =back
3785              
3786             =head2 Valid codes
3787              
3788             =over 4
3789              
3790 0     0   0 =item valid_languages()
3791              
3792 0         0 This method returns a list containing all the valid language codes
3793              
3794 0         0 =item valid_scripts()
3795 0         0  
3796 0         0 This method returns a list containing all the valid script codes
3797 0         0  
3798 0         0 =item valid_regions()
3799 0 0       0  
3800             This method returns a list containing all the valid region codes
3801              
3802             =item valid_variants()
3803              
3804             This method returns a list containing all the valid variant codes
3805 1     1   641  
3806             =item key_aliases()
3807 1 50       15  
3808             This method returns a hash that maps valid keys to their valid aliases
3809              
3810             =item key_names()
3811              
3812             This method returns a hash that maps valid key aliases to their valid keys
3813              
3814             =item valid_keys()
3815              
3816             This method returns a hash of valid keys and the valid type codes you
3817             can have with each key
3818              
3819             =item language_aliases()
3820              
3821             This method returns a hash that maps valid language codes to their valid aliases
3822              
3823 1     1   634 =item region_aliases()
3824              
3825 1         4 This method returns a hash that maps valid region codes to their valid aliases
3826              
3827 1         14 =item variant_aliases()
3828              
3829             This method returns a hash that maps valid variant codes to their valid aliases
3830              
3831             =back
3832              
3833 21 50   21   155 =head2 Information about weeks
  21     21   35  
  21     189   673  
  21         98  
  21         36  
  21         1281  
  189         425  
  189         495  
  189         1250  
  336         5212  
  189         2436  
3834              
3835             There are no standard codes for the days of the weeks so CLDR uses the following
3836             three letter codes to represent unlocalised days
3837              
3838             =over 4
3839              
3840             =item sun
3841              
3842             Sunday
3843              
3844             =item mon
3845              
3846             Monday
3847              
3848             =item tue
3849              
3850             Tuesday
3851              
3852             =item wed
3853              
3854             Wednesday
3855              
3856             =item thu
3857              
3858             Thursday
3859              
3860             =item fri
3861              
3862             Friday
3863              
3864             =item sat
3865 336 100   336   637  
  336 100       643  
  336         580  
  0         0  
  336         396  
  336         2004  
  336         591  
  336         457  
  330         5563  
  6         25  
3866             Saturday
3867              
3868             =back
3869              
3870             =cut
3871              
3872             my ($self, $region_id, $week_data_hash) = @_;
3873            
3874             $region_id //= ( $self->region_id || $self->likely_subtag->region_id );
3875            
3876             return $week_data_hash->{$region_id} if exists $week_data_hash->{$region_id};
3877            
3878             while (1) {
3879             $region_id = $self->region_contained_by()->{$region_id};
3880             return unless defined $region_id;
3881             return $week_data_hash->{$region_id} if exists $week_data_hash->{$region_id};
3882             }
3883             }
3884              
3885             =over 4
3886              
3887             =item week_data_min_days($region_id)
3888              
3889             This method takes an optional region id and returns a the minimum number of days
3890             a week must have to count as the starting week of the new year. It uses the current
3891             locale's region if no region id is passed in.
3892              
3893             =cut
3894              
3895             my ($self, $region_id) = @_;
3896            
3897             my $week_data_hash = $self->_week_data_min_days();
3898             return _week_data($self, $region_id, $week_data_hash);
3899             }
3900              
3901             =item week_data_first_day($region_id)
3902              
3903             This method takes an optional region id and returns the three letter code of the
3904             first day of the week for that region. If no region id is passed in then it
3905             uses the current locale's region.
3906              
3907             =cut
3908              
3909             my ($self, $region_id) = @_;
3910            
3911             if ($self->_test_default_fw) {
3912             return $self->_default_fw;
3913             }
3914            
3915             my $week_data_hash = $self->_week_data_first_day();
3916             my $first_day = _week_data($self, $region_id, $week_data_hash);
3917             $self->_set_default_fw($first_day);
3918             return $first_day;
3919             }
3920              
3921             =item week_data_weekend_start()
3922              
3923             This method takes an optional region id and returns the three letter code of the
3924             first day of the weekend for that region. If no region id is passed in then it
3925             uses the current locale's region.
3926              
3927             =cut
3928              
3929             my ($self, $region_id) = @_;
3930             my $week_data_hash = $self->_week_data_weekend_start();
3931            
3932             return _week_data($self, $region_id, $week_data_hash);
3933             }
3934              
3935             =item week_data_weekend_end()
3936              
3937             This method takes an optional region id and returns the three letter code of the
3938             last day of the weekend for that region. If no region id is passed in then it
3939             uses the current locale's region.
3940              
3941             =cut
3942              
3943             my ($self, $region_id) = @_;
3944             my $week_data_hash = $self->_week_data_weekend_end();
3945            
3946             return _week_data($self, $region_id, $week_data_hash);
3947             }
3948              
3949             =item month_patterns($context, $width, $type)
3950              
3951             The Chinese lunar calendar can insert a leap month after nearly any month of its year;
3952             when this happens, the month takes the name of the preceding month plus a special marker.
3953             The Hindu lunar calendars can insert a leap month before any one or two months of the year;
3954             when this happens, not only does the leap month take the name of the following month plus a
3955             special marker, the following month also takes a special marker. Moreover, in the Hindu
3956             calendar sometimes a month is skipped, in which case the preceding month takes a special marker
3957             plus the names of both months. The monthPatterns() method returns an array ref of month names
3958             with the marker added.
3959              
3960             =cut
3961              
3962             my %month_functions = (
3963             format => {
3964             wide => 'month_format_wide',
3965             abbreviated => 'month_format_abbreviated',
3966             narrow => 'month_format_narrow',
3967             },
3968             'stand-alone' => {
3969             wide => 'month_stand_alone_wide',
3970             abbreviated => 'month_stand_alone_abbreviated',
3971             narrow => 'month_stand_alone_narrow',
3972             }
3973             );
3974              
3975             my ($self, $context, $width, $type) = @_;
3976            
3977             my @months;
3978             if ($context eq 'numeric') {
3979             @months = ( 1 .. 14 );
3980             }
3981             else {
3982             my $months_method = $month_functions{$context}{$width};
3983             my $months = $self->$months_method;
3984             @months = @$months;
3985             }
3986            
3987             my $default_calendar = $self->default_calendar();
3988            
3989             my @bundles = $self->_find_bundle('month_patterns');
3990              
3991             my $result;
3992             BUNDLES: {
3993             foreach my $bundle (@bundles) {
3994             my $month_patterns = $bundle->month_patterns;
3995             if (exists $month_patterns->{$default_calendar}{alias}) {
3996             $default_calendar = $month_patterns->{$default_calendar}{alias};
3997             redo BUNDLES;
3998             }
3999            
4000             # Check for width alias
4001             if (exists $month_patterns->{$default_calendar}{$context}{$width}{alias}) {
4002             $context = $month_patterns->{$default_calendar}{$context}{$width}{alias}{context};
4003             $width = $month_patterns->{$default_calendar}{$context}{$width}{alias}{width};
4004             redo BUNDLES;
4005             }
4006            
4007             $result = $month_patterns->{$default_calendar}{$context}{$width}{$type};
4008             last BUNDLES if $result;
4009 4     4   7 }
4010             if ($default_calendar ne 'gregorian') {
4011 4   33     88 $default_calendar = 'gregorian';
      33        
4012             redo BUNDLES;
4013 4 100       17 }
4014             }
4015 2         3
4016 8         15 if ($result) {
4017 8 50       11 foreach my $month (@months) {
4018 8 100       20 (my $fixed_month = $result) =~ s/\{0\}/$month/g;
4019             $month = $fixed_month;
4020             }
4021             }
4022            
4023             return \@months;
4024             }
4025              
4026             =item cyclic_name_sets($context, $width, $type)
4027              
4028             This method returns an arrayref containing the cyclic names for the locale's
4029             default calendar using the given context, width and type.
4030              
4031             Context can can currently only be c<format>
4032              
4033 1     1 1 4 Width is one of C<abbreviated>, C<narrow> or C<wide>
4034              
4035 1         5 Type is one of C<dayParts>, C<days>, C<months>, C<solarTerms>, C<years> or C<zodiacs>
4036 1         3  
4037             =cut
4038              
4039             my ($self, $context, $width, $type) = @_;
4040            
4041             my @bundles = $self->_find_bundle('cyclic_name_sets');
4042             my $default_calendar = $self->default_calendar();
4043             foreach my $bundle (@bundles) {
4044             my $cyclic_name_set = $bundle->cyclic_name_sets();
4045             NAME_SET: {
4046             if (my $alias_calendar = $cyclic_name_set->{$default_calendar}{alias}) {
4047             $default_calendar = $alias_calendar;
4048 3     3 1 4479 redo NAME_SET;
4049             }
4050 3 100       12
4051 2         14 if (my $type_alias = $cyclic_name_set->{$default_calendar}{$type}{alias}) {
4052             $type = $type_alias;
4053             redo NAME_SET;
4054 1         4 }
4055 1         4
4056 1         15 if (my $width_alias = $cyclic_name_set->{$default_calendar}{$type}{$context}{$width}{alias}) {
4057 1         27 $context = $width_alias->{context};
4058             $type = $width_alias->{name_set};
4059             $width = $width_alias->{type};
4060             redo NAME_SET;
4061             }
4062            
4063             my $return = [
4064             @{ $cyclic_name_set->{$default_calendar}{$type}{$context}{$width} }
4065             {sort { $a <=> $b } keys %{ $cyclic_name_set->{$default_calendar}{$type}{$context}{$width} }}
4066             ];
4067            
4068             return $return if @$return;
4069 1     1 1 3 }
4070 1         4 }
4071             return [];
4072 1         3 }
4073              
4074             =back
4075              
4076             =head2 Region Containment
4077              
4078             =over 4
4079              
4080             =item region_contains()
4081              
4082             This method returns a hash ref keyed on region id. The value is an array ref.
4083             Each element of the array ref is a region id of a region immediately
4084 1     1 1 3 contained in the region used as the key
4085 1         5  
4086             =item region_contained_by()
4087 1         3  
4088             This method returns a hash ref keyed on region id. The value of the hash
4089             is the region id of the immediately containing region.
4090              
4091             =back
4092              
4093             =head2 Numbering Systems
4094              
4095             =over 4
4096              
4097             =item numbering_system()
4098              
4099             This method returns a hash ref keyed on numbering system id which, for a given
4100             locale, can be got by calling the default_numbering_system() method. The values
4101             of the hash are a two element hash ref the keys being C<type> and C<data>. If the
4102             type is C<numeric> then the data is an array ref of characters. The position in the
4103             array matches the numeric value of the character. If the type is C<algorithmic>
4104             then data is the name of the algorithm used to display numbers in that format.
4105              
4106             =back
4107              
4108             =head2 Number Formatting
4109              
4110             =over 4
4111              
4112             =item format_number($number, $format, $currency, $for_cash)
4113              
4114             This method formats the number $number using the format $format. If the format contains
4115             the currency symbol C<¤> then the currency symbol for the currency code in $currency
4116             will be used. If $currency is undef() then the default currency code for the locale
4117 1     1 1 3532 will be used.
4118              
4119 1         56 Note that currency codes are based on region so if you do not pass in a currency
4120 1 50       19 and your locale did not get passed a region in the constructor you are going
4121 0         0 to end up with the L<likely sub tag's|/likely_subtags> idea of the currency. This
4122             functionality may be removed or at least changed to emit a warning in future
4123             releases.
4124 1         16  
4125 1         36 $for_cash is only used during currency formatting. If true then cash rounding
4126 1         27 will be used otherwise financial rounding will be used.
4127              
4128             This function also handles rule based number formatting. If $format is string equivalent
4129 1         3 to one of the current locale's public rule based number formats then $number will be
4130             formatted according to that rule.
4131 1         3  
4132             =item format_currency($number, $for_cash)
4133 1         7  
4134             This method formats the number $number using the default currency and currency format for the locale.
4135 1         2 If $for_cash is a true value then cash rounding will be used otherwise financial rounding will be used.
  2         4  
4136 2         8  
4137 2 50       8 =item add_currency_symbol($format, $symbol)
4138 0         0  
4139 0         0 This method returns the format with the currency symbol $symbol correctly inserted
4140             into the format
4141              
4142             =item parse_number_format($format, $currency, $currency_data, $for_cash)
4143 2 100       7  
4144 1         4 This method parses a CLDR numeric format string into a hash ref containing data used to
4145 1         3 format a number. If a currency is being formatted then $currency contains the
4146 1         4 currency code, $currency_data is a hashref containing the currency rounding
4147             information and $for_cash is a flag to signal cash or financial rounding.
4148              
4149 1         2 This should probably be a private function.
4150 1 50       4  
4151             =item round($number, $increment, $decimal_digits)
4152 0 0       0  
4153 0         0 This method returns $number rounded to the nearest $increment with $decimal_digits
4154 0         0 digits after the decimal point
4155              
4156             =item get_formatted_number($number, $format, $currency_data, $for_cash)
4157              
4158 1 50       3 This method takes the $format produced by parse_number_format() and uses it to
4159 1         3 parse $number. It returns a string containing the parsed number. If a currency
4160 12         19 is being formatted then $currency_data is a hashref containing the currency
4161 12         16 rounding information and $for_cash is a flag to signal cash or financial rounding.
4162              
4163             =item get_digits()
4164              
4165 1         11 This method returns an array containing the digits used by the locale, The order of the
4166             array is the order of the digits. It the locale's numbering system is C<algorithmic> it
4167             will return C<[0,1,2,3,4,5,6,7,8,9]>
4168              
4169             =item default_numbering_system()
4170              
4171             This method returns the numbering system id for the locale.
4172              
4173             =item default_currency_format()
4174              
4175             This method returns the locale's currenc format. This can be used by the number formatting code to
4176             correctly format the locale's currency
4177              
4178             =item currency_format($format_type)
4179              
4180             This method returns the format string for the currencies for the locale
4181              
4182 1     1 1 4 There are two types of formatting I<standard> and I<accounting> you can
4183             pass C<standard> or C<accounting> as the paramater to the method to pick one of
4184 1         4 these ot it will use the locales default
4185 1         10  
4186 1         2 =cut
4187 2         7  
4188             my ($self, $default_currency_format) = @_;
4189 2 50       3
  3         9  
4190 0         0 die "Invalid Currency format: must be one of 'standard' or 'accounting'"
4191 0         0 if defined $default_currency_format
4192             && $default_currency_format ne 'standard'
4193             && $default_currency_format ne 'accounting';
4194 3 50       8
4195 0         0 $default_currency_format //= $self->default_currency_format;
4196 0         0 my @bundles = $self->_find_bundle('number_currency_formats');
4197            
4198             my $format = {};
4199 3 100       10 my $default_numbering_system = $self->default_numbering_system();
4200 1         2 foreach my $bundle (@bundles) {
4201 1         2 NUMBER_SYSTEM: {
4202 1         2 $format = $bundle->number_currency_formats();
4203 1         3 if (exists $format->{$default_numbering_system}{alias}) {
4204             $default_numbering_system = $format->{$default_numbering_system}{alias};
4205             redo NUMBER_SYSTEM;
4206             }
4207 2         7
4208 2         3 if (exists $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}{alias}) {
  31         31  
  2         13  
4209             $default_currency_format = $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}{alias};
4210             redo NUMBER_SYSTEM;
4211 2 100       16 }
4212             }
4213            
4214 0         0 last if exists $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}
4215             }
4216            
4217             $default_currency_format = 'accounting' if $default_currency_format eq 'account';
4218            
4219             return join ';',
4220             $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}{positive},
4221             defined $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}{negative}
4222             ? $format->{$default_numbering_system}{pattern}{default}{$default_currency_format}{negative}
4223             : ();
4224             }
4225              
4226             =back
4227              
4228             =head2 Measurement Information
4229              
4230             =over 4
4231              
4232             =item measurement_system()
4233              
4234             This method returns a hash ref keyed on region, the value being the measurement system
4235             id for the region. If the region you are interested in is not listed use the
4236             region_contained_by() method until you find an entry.
4237              
4238             =item paper_size()
4239              
4240             This method returns a hash ref keyed on region, the value being the paper size used
4241             in that region. If the region you are interested in is not listed use the
4242             region_contained_by() method until you find an entry.
4243              
4244             =back
4245              
4246             =head2 Likely Tags
4247              
4248             =over 4
4249              
4250             =item likely_subtags()
4251              
4252             A full locale tag requires, as a minimum, a language, script and region code. However for
4253             some locales it is possible to infer the missing element if the other two are given, e.g.
4254             given C<en_GB> you can infer the script will be latn. It is also possible to fill in the
4255             missing elements of a locale with sensible defaults given sufficient knowledge of the layout
4256             of the CLDR data and usage patterns of locales around the world.
4257              
4258             This function returns a hash ref keyed on partial locale id's with the value being the locale
4259             id for the most likely language, script and region code for the key.
4260              
4261             =item likely_subtag()
4262              
4263             This method returns a Locale::CLDR object with any missing elements from the language, script or
4264             region, filled in with data from the likely_subtags hash
4265              
4266             =back
4267              
4268             =head2 Currency Information
4269              
4270             =over 4
4271              
4272             =item currency_fractions()
4273              
4274             This method returns a hash ref keyed on currency id. The value is a hash ref containing four keys.
4275             The keys are
4276              
4277             =over 8
4278              
4279             =item digits
4280              
4281             The number of decimal digits normally formatted.
4282              
4283             =item rounding
4284              
4285             The rounding increment, in units of 10^-digits.
4286              
4287             =item cashdigits
4288              
4289             The number of decimal digits to be used when formatting quantities used in cash transactions (as opposed
4290             to a quantity that would appear in a more formal setting, such as on a bank statement).
4291              
4292             =item cashrounding
4293              
4294             The cash rounding increment, in units of 10^-cashdigits.
4295              
4296             =back
4297              
4298             =item default_currency($region_id)
4299              
4300             This method returns the default currency id for the region id.
4301             If no region id is given then the current locale's is used
4302              
4303             =cut
4304              
4305             my ($self, $region_id) = @_;
4306            
4307             return $self->_default_cu if $self->_test_default_cu();
4308            
4309             $region_id //= $self->region_id;
4310            
4311             if (! $region_id) {
4312             $region_id = $self->likely_subtag->region_id;
4313             warn "Locale::CLDR::default_currency:- No region given using $region_id at ";
4314             }
4315            
4316             my $default_currencies = $self->_default_currency;
4317            
4318             return $default_currencies->{$region_id} if exists $default_currencies->{$region_id};
4319            
4320             while (1) {
4321             $region_id = $self->region_contained_by($region_id);
4322             last unless $region_id;
4323             if (exists $default_currencies->{$region_id}) {
4324             $self->_set_default_cu($default_currencies->{$region_id});
4325             return $default_currencies->{$region_id};
4326             }
4327             }
4328             }
4329              
4330             =item currency_symbol($currency_id)
4331              
4332 22     22 1 27098 This method returns the currency symbol for the given currency id in the current locale.
4333             If no currency id is given it uses the locale's default currency
4334 22 50 100     124  
      66        
4335             =cut
4336              
4337             my ($self, $currency_id) = @_;
4338            
4339 22   66     160 $currency_id //= $self->default_currency;
4340 22         90
4341             my @bundles = reverse $self->_find_bundle('currencies');
4342 22         163 foreach my $bundle (@bundles) {
4343 22         110 my $symbol = $bundle->currencies()->{uc $currency_id}{symbol};
4344 22         54 return $symbol if $symbol;
4345             }
4346 22         48
  22         97  
4347 22 50       112 return '';
4348 0         0 }
4349 0         0  
4350             =back
4351              
4352 22 50       112 =head2 Calendar Information
4353 0         0  
4354 0         0 =over 4
4355              
4356             =item calendar_preferences()
4357              
4358 22 50       74 This method returns a hash ref keyed on region id. The values are array refs containing the preferred
4359             calendar id's in order of preference.
4360              
4361 22 100       70 =item default_calendar($region)
4362              
4363             This method returns the default calendar id for the given region. If no region id given it
4364             used the region of the current locale.
4365              
4366             =back
4367 22 100       513  
4368             =cut
4369              
4370             has 'Lexicon' => (
4371             isa => HashRef,
4372             init_arg => undef,
4373             is => 'ro',
4374             clearer => 'reset_lexicon',
4375             default => sub { return {} },
4376             );
4377              
4378             my ($self, $key, $value) = @_;
4379             $self->Lexicon()->{$key} = $value;
4380             }
4381              
4382             my ($self, $key) = @_;
4383             return $self->Lexicon()->{$key};
4384             }
4385              
4386             =head2 Make text emulation
4387              
4388             Locale::CLDR has a Locle::Maketext alike system called LocaleText
4389              
4390             =head3 The Lexicon
4391              
4392             The Lexicon stores the items that will be localized by the localetext method. You
4393             can manipulate it by the following methods
4394              
4395             =over 4
4396              
4397             =item reset_lexicon()
4398              
4399             This method empties the lexicon
4400              
4401             =item add_to_lexicon($identifier => $localized_text, ...)
4402              
4403             This method adds data to the locales lexicon.
4404              
4405             $identifier is the string passed to localetext() to get the localised version of the text. Each identfier is unique
4406              
4407             $localized_text is the value that is used to create the current locales version of the string. It uses L<Locale::Maketext|Locale::Maketext's>
4408             bracket formatting syntax with some additional methods and some changes to how numerate() works. See below
4409              
4410             Multiple entries can be added by one call to add_to_lexicon()
4411              
4412             =item add_plural_to_lexicon( $identifier => { $pluralform => $localized_text, ... }, ... )
4413              
4414             $identifier is the string passed to localetext() to get the localised version of the text. Each identfier is unique and must be different
4415             from the identifiers given to add_to_lexicon()
4416              
4417             $pluralform is one of the CLDR's plural forms, these are C<zero, one, two, few, many> and C<other>
4418              
4419             $localized_text is the value that is used to create the current locales version of the string. It uses L<Locale::Maketext|Locale::Maketext's>
4420             bracket formatting syntax with some additional methods and some changes to how numerate() works. See below
4421              
4422             =back
4423              
4424             =head3 Format of maketext strings
4425              
4426             The make text emulation uses the same bracket and escape mecanism as Locale::Maketext. ie ~ is used
4427             to turn a [ from a metta character into a normal one and you need to doubble up the ~ if you want it to appear in
4428             your output. This allows you to embed into you output constructs that will change depending on the locale.
4429              
4430             =head4 Examples of output strings
4431              
4432             Due to the way macro expantion works in localetext any element of the [ ... ] construct except the first may be
4433             substutied by a _1 marker
4434              
4435             =over 4
4436              
4437             =item You scored [numf,_1]
4438              
4439             localetext() will replace C<[numf,_1]> with the correctly formatted version of the number you passed in as the first paramater
4440             after the identifier.
4441              
4442             =item You have [plural,_1,coins]
4443              
4444             This will substutite the correct plural form of the coins text into the string
4445              
4446             =item This is [gnum,_1,type,gender,declention]
4447              
4448             This will substute the correctly gendered spellout rule for the number given in _1
4449              
4450 17     17 1 48 =cut
4451              
4452 17 100       81 my $self = shift;
4453             die "Incorrect number of peramaters to add_to_lexicon()\n" if @_ % 2;
4454 9   33     247 my %parameters = @_;
4455              
4456 9 50       27 foreach my $identifier (keys %parameters) {
4457 0         0 $self->_add_to_lexicon( $identifier => { default => $self->_parse_localetext_text($parameters{$identifier})});
4458 0         0 }
4459             }
4460              
4461 9         38 my $self = shift;
4462             die "Incorrect number of peramaters to add_to_lexicon()\n" if @_ % 2;
4463 9 50       54 my %parameters = @_;
4464              
4465 0         0 foreach my $identifier (keys %parameters) {
4466 0         0 my %plurals;
4467 0 0       0 foreach my $plural ( keys %{$parameters{$identifier}} ) {
4468 0 0       0 die "Invalid plural form $plural for $identifier\n"
4469 0         0 unless grep { $_ eq $plural } qw(zero one two few many other);
4470 0         0  
4471             $plurals{$plural} = $self->_parse_localetext_text($parameters{$identifier}{$plural}, 1);
4472             }
4473            
4474             $self->_add_to_lexicon( $identifier => \%plurals );
4475             }
4476             }
4477              
4478             # This method converts the string passed in into a sub ref and parsed out the bracketed
4479             # elements into method calls on the locale object
4480             my %methods = (
4481             gnum => '_make_text_gnum',
4482             numf => '_make_text_numf',
4483 17     17 1 38 plural => '_make_text_plural',
4484             expand => '_make_text_expand',
4485 17   33     48 );
4486              
4487 17         49 my ($self, $text, $is_plural) = @_;
4488 17         124
4489 17         138 my $original = $text;
4490 17 50       93 # Short circuit if no [ in text
4491             $text //= '';
4492             return sub { $text } if $text !~ /\[/;
4493 0         0 my $in_group = 0;
4494            
4495             my $sub = 'sub { join \'\' ';
4496             # loop over text to find the first bracket group
4497             while (length $text) {
4498             my ($raw) = $text =~ /^ ( (?: (?: ~~ )*+ ~ \[ | [^\[] )++ ) /x;
4499             if (length $raw) {
4500             $text =~ s/^ ( (?: (?: ~~ )*+ ~ \[ | [^\[] )++ ) //gx;
4501             # Fix up escapes
4502             $raw =~ s/(?:~~)*+\K~\[/[/g;
4503             $raw =~ s/(?:~~)*+\K~,/,/g;
4504             $raw =~ s/~~/~/g;
4505            
4506             # Escape stuff for perl
4507             $raw =~ s/\\/\\\\/g;
4508             $raw =~ s/'/\\'/g;
4509            
4510             $sub .= ", '$raw'";
4511             }
4512            
4513             last unless length $text; # exit loop if nothing left to do
4514             my ($method) = $text =~ /^( \[ [^\]]+? \] )/x;
4515             $text =~ s/^( \[ [^\]]+? \] )//xg;
4516            
4517             # check for no method but have text left
4518             die "Malformatted make text data '$original'"
4519             if ! length $method && length $text;
4520            
4521             # Check for a [ in the method as this is an error
4522             die "Malformatted make text data '$original'"
4523             if $method =~ /^\[.*\[/;
4524            
4525 3     3   7 # check for [_\d+] This just adds a stringified version of the params
4526 3         16 if ( my ($number) = $method =~ / \[ \s* _ [0-9]+ \s* \] /x ) {
4527             if ($number == 0) {# Special case
4528             $sub .= ', "@_[1 .. @_ -1 ]"';
4529             }
4530 9     9   16 else {
4531 9         31 $sub .= ', "$_[$number]"';
4532             }
4533             next;
4534             }
4535            
4536             # now we should have [ method, param, ... ]
4537             # strip of the [ and ]
4538             $method =~ s/ \[ \s* (.*?) \s* \] /$1/x;
4539            
4540             # sort out ~, and ~~
4541             $method =~ s/(?:~~)*+\K~,/\x{00}/g;
4542             $method =~ s/~~/~/g;
4543             ($method, my @params) = split /,/, $method;
4544            
4545             # if $is_plural is true we wont have a method
4546             if ($is_plural) {
4547             $params[0] = $method;
4548             $method = 'expand';
4549             }
4550            
4551             die "Unknown method $method in make text data '$original'"
4552             unless exists $methods{lc $method};
4553              
4554             @params =
4555             map { s/([\\'])/\\$1/g; $_ }
4556             map { s/_([0-9])+/\$_[$1]/gx; $_ }
4557             map { s/\x{00}/,/g; $_ }
4558             @params;
4559            
4560             $sub .= ", \$_[0]->$methods{lc $method}("
4561             . (scalar @params ? '"' : '')
4562             . join('","', @params)
4563             . (scalar @params ? '"' : '')
4564             . '), ';
4565             }
4566            
4567             $sub .= '}';
4568            
4569             return eval "$sub";
4570             }
4571              
4572             my ($self, $number, $type, $gender, $declention) = @_;
4573             no if $] >= 5.017011, warnings => 'experimental::smartmatch';
4574             $type //= 'ordinal';
4575             $gender //= 'neuter';
4576            
4577             die "Invalid number type ($type) in makelocale\n"
4578             unless $type ~~ [qw(ordinal cardinal)];
4579            
4580             die "Invalid gender ($gender) in makelocale\n"
4581             unless $gender ~~ [qw(masculine feminine nuter)];
4582              
4583             my @names = (
4584             ( defined $declention ? "spellout-$type-$gender-$declention" : ()),
4585             "spellout-$type-$gender",
4586             "spellout-$type",
4587             );
4588            
4589             my %formats;
4590             @formats{ grep { /^spellout-$type/ } $self->_get_valid_algorithmic_formats() } = ();
4591            
4592             foreach my $name (@names) {
4593             return $self->format_number($number, $name) if exists $formats{$name};
4594             }
4595            
4596             return $self->format_number($number);
4597             }
4598              
4599             my ( $self, $number ) = @_;
4600            
4601 1     1 1 7 return $self->format_number($number);
4602 1 50       4 }
4603 1         5  
4604             my ($self, $number, $identifier) = @_;
4605 1         4
4606 1         3 my $plural = $self->plural($number);
4607            
4608             my $text = $self->_get_from_lexicon($identifier)->{$plural};
4609             $number = $self->_make_text_numf($number);
4610            
4611 1     1 1 1038 return $self->$text($number);
4612 1 50       4 }
4613 1         5  
4614             shift;
4615 1         4 return @_;
4616 2         3 }
4617 2         2  
  2         6  
4618             =item localetext($identifer, @parameters)
4619 8 50       13  
  48         69  
4620             This method looks up the identifier in the current locales lexicon and then formats the returned text
4621 8         17 as part in the current locale the identifier is the same as the identifier passed into the
4622             add_to_lexicon() metod. The parameters are the values required by the [ ... ] expantions in the
4623             localised text.
4624 2         9  
4625             =cut
4626              
4627             my ($self, $identifier, @params) = @_;
4628            
4629             my $text = $self->_get_from_lexicon($identifier);
4630            
4631             if ( ref $params[-1] eq 'HASH' ) {
4632             my $plural = $params[-1]{plural};
4633             return $text->{$plural}($self, @params[0 .. @params -1]);
4634             }
4635             return $text->{default}($self, @params);
4636             }
4637              
4638 9     9   15 =back
4639              
4640 9         10 =head2 Collation
4641              
4642 9   50     15 =over 4
4643 9 100   0   22  
  0         0  
4644 7         10 =item collation()
4645              
4646 7         8 This method returns a Locale::CLDR::Collator object. This is still in development. Future releases will
4647             try and match the API from L<Unicode::Collate> as much as possible and add tailoring for locales.
4648 7         12  
4649 8         27 =back
4650 8 100       131  
4651 2         9 =cut
4652              
4653 2         4 my $self = shift;
4654 2         4
4655 2         4 my %params = @_;
4656             $params{type} //= $self->_collation_type;
4657             $params{alternate} //= $self->_collation_alternate;
4658 2         3 $params{backwards} //= $self->_collation_backwards;
4659 2         3 $params{case_level} //= $self->_collation_case_level;
4660             $params{case_ordering} //= $self->_collation_case_ordering;
4661 2         3 $params{normalization} //= $self->_collation_normalization;
4662             $params{numeric} //= $self->_collation_numeric;
4663             $params{reorder} //= $self->_collation_reorder;
4664 8 50       19 $params{strength} //= $self->_collation_strength;
4665 8         24 $params{max_variable} //= $self->_collation_max_variable;
4666 8         23
4667             return Locale::CLDR::Collator->new(locale => $self, %params);
4668             }
4669 8 50 33     17  
4670             my ($self, $type) = @_;
4671            
4672             my @bundles = reverse $self->_find_bundle('collation');
4673 8 50       15
4674             my $override = '';
4675             foreach my $bundle (@bundles) {
4676             last if $override = $bundle->collation()->{$type};
4677 8 50       19 }
4678 0 0       0
4679 0         0 if ($type ne 'standard' && ! $override) {
4680             foreach my $bundle (@bundles) {
4681             last if $override = $bundle->collation()->{standard};
4682 0         0 }
4683             }
4684 0         0
4685             return $override || [];
4686             }
4687            
4688             my $self = shift;
4689 8         34
4690             return $self->extensions()->{co} if ref $self->extensions() && $self->extensions()->{co};
4691             my @bundles = reverse $self->_find_bundle('collation_type');
4692 8         13 my $collation_type = '';
4693 8         9
4694 8         18 foreach my $bundle (@bundles) {
4695             last if $collation_type = $bundle->collation_type();
4696             }
4697 8 100       15
4698 6         8 return $collation_type || 'standard';
4699 6         8 }
4700              
4701             my $self = shift;
4702            
4703 8 50       18 return $self->extensions()->{ka} if ref $self->extensions() && $self->extensions()->{ka};
4704             my @bundles = reverse $self->_find_bundle('collation_alternate');
4705             my $collation_alternate = '';
4706 10         16
  10         16  
4707 10         34 foreach my $bundle (@bundles) {
  10         17  
4708 8         10 last if $collation_alternate = $bundle->collation_alternate();
  10         14  
  10         19  
4709             }
4710            
4711 8 50       41 return $collation_alternate || 'noignore';
    50          
4712             }
4713              
4714             my $self = shift;
4715            
4716             return $self->extensions()->{kb} if ref $self->extensions() && $self->extensions()->{kb};
4717             my @bundles = reverse $self->_find_bundle('collation_backwards');
4718 7         10 my $collation_backwards = '';
4719            
4720 7         560 foreach my $bundle (@bundles) {
4721             last if $collation_backwards = $bundle->collation_backwards();
4722             }
4723            
4724 0     0   0 return $collation_backwards || 'noignore';
4725 21     21   230 }
  21         60  
  21         206  
4726 0   0     0  
4727 0   0     0 my $self = shift;
4728            
4729 0 0       0 return $self->extensions()->{kc} if ref $self->extensions() && $self->extensions()->{kc};
4730             my @bundles = reverse $self->_find_bundle('collation_case_level');
4731             my $collation_case_level = '';
4732 0 0       0
4733             foreach my $bundle (@bundles) {
4734             last if $collation_case_level = $bundle->collation_case_level();
4735 0 0       0 }
4736            
4737             return $collation_case_level || 'false';
4738             }
4739              
4740             my $self = shift;
4741 0         0
4742 0         0 return $self->extensions()->{kf} if ref $self->extensions() && $self->extensions()->{kf};
  0         0  
4743             my @bundles = reverse $self->_find_bundle('collation_case_ordering');
4744 0         0 my $collation_case_ordering = '';
4745 0 0       0
4746             foreach my $bundle (@bundles) {
4747             last if $collation_case_ordering = $bundle->collation_case_ordering();
4748 0         0 }
4749            
4750             return $collation_case_ordering || 'false';
4751             }
4752 6     6   9  
4753             my $self = shift;
4754 6         22
4755             return $self->extensions()->{kk} if ref $self->extensions() && $self->extensions()->{kk};
4756             my @bundles = reverse $self->_find_bundle('collation_normalization');
4757             my $collation_normalization = '';
4758 6     6   14
4759             foreach my $bundle (@bundles) {
4760 6         25 last if $collation_normalization = $bundle->collation_normalization();
4761             }
4762 6         15
4763 6         15 return $collation_normalization || 'true';
4764             }
4765 6         105  
4766             my $self = shift;
4767            
4768             return $self->extensions()->{kn} if ref $self->extensions() && $self->extensions()->{kn};
4769 6     6   8 my @bundles = reverse $self->_find_bundle('collation_numeric');
4770 6         42 my $collation_numeric = '';
4771            
4772             foreach my $bundle (@bundles) {
4773             last if $collation_numeric = $bundle->collation_numeric();
4774             }
4775            
4776             return $collation_numeric || 'false';
4777             }
4778              
4779             my $self = shift;
4780            
4781             return $self->extensions()->{kr} if ref $self->extensions() && $self->extensions()->{kr};
4782             my @bundles = reverse $self->_find_bundle('collation_reorder');
4783 3     3 1 15 my $collation_reorder = [];
4784            
4785 3         9 foreach my $bundle (@bundles) {
4786             last if ref( $collation_reorder = $bundle->collation_reorder()) && @$collation_reorder;
4787 3 50       10 }
4788 0         0
4789 0         0 return $collation_reorder || [];
4790             }
4791 3         58  
4792             my $self = shift;
4793            
4794             my $collation_strength = ref $self->extensions() && $self->extensions()->{ks};
4795             if ($collation_strength) {
4796             $collation_strength =~ s/^level//;
4797             $collation_strength = 5 unless ($collation_strength + 0);
4798             return $collation_strength;
4799             }
4800            
4801             my @bundles = reverse $self->_find_bundle('collation_strength');
4802             $collation_strength = 0;
4803            
4804             foreach my $bundle (@bundles) {
4805             last if $collation_strength = $bundle->collation_strength();
4806             }
4807            
4808             return $collation_strength || 3;
4809             }
4810 5     5 1 22078  
4811             my $self = shift;
4812 5         20
4813 5   33     35 return $self->extensions()->{kv} if ref $self->extensions() && $self->extensions()->{kv};
4814 5   33     28 my @bundles = reverse $self->_find_bundle('collation_max_variable');
4815 5   33     29 my $collation_max_variable = '';
4816 5   33     24
4817 5   33     27 foreach my $bundle (@bundles) {
4818 5   33     27 last if $collation_max_variable = $bundle->collation_max_variable();
4819 5   33     25 }
4820 5   33     30
4821 5   66     20 return $collation_max_variable || 3;
4822 5   33     27 }
4823              
4824 5         84 =head1 Locales
4825              
4826             Other locales can be found on CPAN. You can install Language packs from the
4827             Locale::CLDR::Locales::* packages. You will in future be able to install language
4828 5     5   14 packs for a given region by looking for a Bundle::Locale::CLDR::* package.
4829              
4830 5         18 If you are looking for a language pack that is not yet published then get hold of
4831             the version 0.25.4 from http://search.cpan.org/CPAN/authors/id/J/JG/JGNI/Locale-CLDR-v0.25.4.tar.gz
4832 5         36 which has data for all locals alternatively you can get hold of the latest version of the
4833 5         10 code from git hub at https://github.com/ThePilgrim/perlcldr
4834 0 0       0  
4835             =head1 AUTHOR
4836              
4837 5 50 33     20 John Imrie, C<< <JGNI at cpan dot org> >>
4838 0         0  
4839 0 0       0 =head1 BUGS
4840              
4841             Please report any bugs or feature requests to C<bug-locale-cldr at rt.cpan.org>, or through
4842             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Locale-CLDR>. I will be notified, and then you'll
4843 5   50     29 automatically be notified of progress on your bug as I make changes.
4844              
4845             =head1 SUPPORT
4846              
4847 5     5   9 You can find documentation for this module with the perldoc command.
4848              
4849 5 0 33     29 perldoc Locale::CLDR
4850 5         19  
4851 5         40 You can also look for information at:
4852              
4853 5         12 =over 4
4854 0 0       0  
4855             =item * RT: CPAN's request tracker
4856              
4857 5   50     34 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Locale-CLDR>
4858              
4859             =item * AnnoCPAN: Annotated CPAN documentation
4860              
4861 5     5   10 L<http://annocpan.org/dist/Locale-CLDR>
4862              
4863 5 0 33     18 =item * CPAN Ratings
4864 5         13  
4865 5         29 L<http://cpanratings.perl.org/d/Locale-CLDR>
4866              
4867 5         12 =item * Search CPAN
4868 0 0       0  
4869             L<http://search.cpan.org/dist/Locale-CLDR/>
4870              
4871 5   50     28 =back
4872              
4873              
4874             =head1 ACKNOWLEDGEMENTS
4875 5     5   8  
4876             Everyone at the Unicode Consortium for providing the data.
4877 5 0 33     18  
4878 5         11 Karl Williams for his tireless work on Unicode in the Perl
4879 5         27 regex engine.
4880              
4881 5         10 =head1 COPYRIGHT & LICENSE
4882 0 0       0  
4883             Copyright 2009-2015 John Imrie.
4884              
4885 5   50     29 This program is free software; you can redistribute it and/or modify it
4886             under the terms of either: the GNU General Public License as published
4887             by the Free Software Foundation; or the Artistic License.
4888              
4889 5     5   9 See http://dev.perl.org/licenses/ for more information.
4890              
4891 5 0 33     17 =cut
4892 5         10  
4893 5         29 1; # End of Locale::CLDR