File Coverage

blib/lib/Locale/CLDR.pm
Criterion Covered Total %
statement 1235 1662 74.3
branch 276 562 49.1
condition 134 316 42.4
subroutine 179 213 84.0
pod 56 58 96.5
total 1880 2811 66.8


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