File Coverage

blib/lib/Locale/CLDR.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


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