line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::Usul::L10N; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
65995
|
use namespace::autoclean; |
|
3
|
|
|
|
|
13428
|
|
|
3
|
|
|
|
|
51
|
|
4
|
|
|
|
|
|
|
|
5
|
3
|
|
|
3
|
|
652
|
use Class::Null; |
|
3
|
|
|
|
|
260
|
|
|
3
|
|
|
|
|
75
|
|
6
|
3
|
|
|
3
|
|
318
|
use Class::Usul::Constants qw( FALSE LANG NUL SEP TRUE ); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
22
|
|
7
|
3
|
|
|
|
|
20
|
use Class::Usul::Functions qw( assert is_arrayref |
8
|
3
|
|
|
3
|
|
2783
|
is_hashref merge_attributes ); |
|
3
|
|
|
|
|
9
|
|
9
|
3
|
|
|
3
|
|
1042
|
use Class::Usul::Types qw( ArrayRef Bool HashRef Logger SimpleStr Str ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
19
|
|
10
|
3
|
|
|
3
|
|
4901
|
use File::DataClass::Types qw( Directory Path ); |
|
3
|
|
|
|
|
27397
|
|
|
3
|
|
|
|
|
23
|
|
11
|
3
|
|
|
3
|
|
4083
|
use File::Gettext; |
|
3
|
|
|
|
|
125183
|
|
|
3
|
|
|
|
|
94
|
|
12
|
3
|
|
|
3
|
|
19
|
use File::Gettext::Constants qw( CONTEXT_SEP LOCALE_DIRS ); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
140
|
|
13
|
3
|
|
|
3
|
|
17
|
use File::Spec::Functions qw( tmpdir ); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
96
|
|
14
|
3
|
|
|
3
|
|
15
|
use Try::Tiny; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
136
|
|
15
|
3
|
|
|
3
|
|
14
|
use Unexpected::Functions qw( inflate_placeholders ); |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
15
|
|
16
|
3
|
|
|
3
|
|
734
|
use Moo; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
13
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Public attributes |
19
|
0
|
|
|
0
|
|
0
|
has 'l10n_attributes' => is => 'lazy', isa => HashRef, builder => sub { {} }; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has 'locale' => is => 'lazy', isa => SimpleStr, default => LANG; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
has 'localedir' => is => 'lazy', isa => Path, coerce => TRUE, |
24
|
0
|
|
|
0
|
|
0
|
builder => sub { LOCALE_DIRS->[ 0 ] }; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has 'log' => is => 'ro', isa => Logger, |
27
|
0
|
|
|
0
|
|
0
|
builder => sub { Class::Null->new }; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
has 'tempdir' => is => 'lazy', isa => Directory, coerce => TRUE, |
30
|
0
|
|
|
0
|
|
0
|
builder => sub { tmpdir }; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Private attributes |
33
|
|
|
|
|
|
|
has '_domains' => is => 'lazy', isa => ArrayRef[Str], builder => sub { |
34
|
5
|
|
50
|
5
|
|
123
|
$_[ 0 ]->l10n_attributes->{domains} // [ 'messages' ] }, |
35
|
|
|
|
|
|
|
reader => 'domains'; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
has '_source_name' => is => 'lazy', isa => SimpleStr, builder => sub { |
38
|
5
|
|
50
|
5
|
|
171
|
$_[ 0 ]->l10n_attributes->{source_name} // 'po' }, |
39
|
|
|
|
|
|
|
reader => 'source_name'; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
has '_use_country' => is => 'lazy', isa => Bool, builder => sub { |
42
|
3
|
|
50
|
3
|
|
78
|
$_[ 0 ]->l10n_attributes->{use_country} // FALSE }, |
43
|
|
|
|
|
|
|
reader => 'use_country'; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Class attributes |
46
|
|
|
|
|
|
|
my $domain_cache = {}; my $locale_cache = {}; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Private methods |
49
|
|
|
|
|
|
|
my $_extract_lang_from = sub { |
50
|
|
|
|
|
|
|
my ($self, $locale) = @_; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
exists $locale_cache->{ $locale } and return $locale_cache->{ $locale }; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my $sep = $self->use_country ? '.' : '_'; |
55
|
|
|
|
|
|
|
my $lang = (split m{ \Q$sep\E }msx, $locale.$sep )[ 0 ]; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
return $locale_cache->{ $locale } = $lang; |
58
|
|
|
|
|
|
|
}; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
my $_load_domains = sub { |
61
|
|
|
|
|
|
|
my ($self, $args) = @_; my $charset; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
assert $self, sub { $args->{locale} }, 'No locale id'; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $locale = $args->{locale} or return; |
66
|
|
|
|
|
|
|
my $lang = $self->$_extract_lang_from( $locale ); |
67
|
|
|
|
|
|
|
my $names = $args->{domains} // $args->{domain_names} // $self->domains; |
68
|
|
|
|
|
|
|
my @names = grep { defined and length } @{ $names }; |
69
|
|
|
|
|
|
|
my $key = $lang.SEP.(join '+', @names ); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
defined $domain_cache->{ $key } and return $domain_cache->{ $key }; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my $attrs = { %{ $self->l10n_attributes }, builder => $self, |
74
|
|
|
|
|
|
|
source_name => $self->source_name, }; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
defined $self->localedir and $attrs->{localedir} = $self->localedir; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
$locale =~ m{ \A (?: [a-z][a-z] ) |
79
|
|
|
|
|
|
|
(?: (?:_[A-Z][A-Z] )? \. ( [-_A-Za-z0-9]+ )? )? |
80
|
|
|
|
|
|
|
(?: \@[-_A-Za-z0-9=;]+ )? \z }msx and $charset = $1; |
81
|
|
|
|
|
|
|
$charset and $attrs->{charset} = $charset; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $domain = try { File::Gettext->new( $attrs )->load( $lang, @names ) } |
84
|
|
|
|
|
|
|
catch { $self->log->error( $_ ); return }; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
return $domain ? $domain_cache->{ $key } = $domain : undef; |
87
|
|
|
|
|
|
|
}; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $_gettext = sub { |
90
|
|
|
|
|
|
|
my ($self, $key, $args) = @_; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
my $count = $args->{count} || 1; |
93
|
|
|
|
|
|
|
my $default = $args->{no_default} ? NUL : $key; |
94
|
|
|
|
|
|
|
my $domain = $self->$_load_domains( $args ) |
95
|
|
|
|
|
|
|
or return ($default, $args->{plural_key})[ $count > 1 ] // $default; |
96
|
|
|
|
|
|
|
# Select either singular or plural translation |
97
|
|
|
|
|
|
|
my ($nplurals, $plural) = (1, 0); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
if ($count > 1) { # Some languages have more than one plural form |
100
|
|
|
|
|
|
|
($nplurals, $plural) = $domain->{plural_func}->( $count ); |
101
|
|
|
|
|
|
|
defined $nplurals or $nplurals = 0; |
102
|
|
|
|
|
|
|
defined $plural or $plural = 0; |
103
|
|
|
|
|
|
|
$plural > $nplurals and $plural = $nplurals; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $id = defined $args->{context} |
107
|
|
|
|
|
|
|
? $args->{context}.CONTEXT_SEP.$key : $key; |
108
|
|
|
|
|
|
|
my $msgs = $domain->{ $self->source_name } // {}; |
109
|
|
|
|
|
|
|
my $msg = $msgs->{ $id } // {}; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
return @{ $msg->{msgstr} // [] }[ $plural ] // $default; |
112
|
|
|
|
|
|
|
}; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Construction |
115
|
|
|
|
|
|
|
around 'BUILDARGS' => sub { |
116
|
|
|
|
|
|
|
my ($orig, $class, @args) = @_; my $attr = $orig->( $class, @args ); |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
my $builder = $attr->{builder} or return $attr; |
119
|
|
|
|
|
|
|
my $config = $builder->can( 'config' ) ? $builder->config : {}; |
120
|
|
|
|
|
|
|
my $keys = [ qw( l10n_attributes locale localedir tempdir ) ]; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
merge_attributes $attr, $builder, [ 'log' ]; |
123
|
|
|
|
|
|
|
merge_attributes $attr, $config, $keys; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
return $attr; |
126
|
|
|
|
|
|
|
}; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Public methods |
129
|
|
|
|
|
|
|
sub get_po_header { |
130
|
1
|
|
|
1
|
1
|
477
|
my ($self, $args) = @_; |
131
|
|
|
|
|
|
|
|
132
|
1
|
50
|
50
|
|
|
6
|
my $domain = $self->$_load_domains( $args // {} ) or return {}; |
133
|
1
|
50
|
|
|
|
5
|
my $header = $domain->{po_header} or return {}; |
134
|
|
|
|
|
|
|
|
135
|
1
|
|
50
|
|
|
6
|
return $header->{msgstr} // {}; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub invalidate_cache { |
139
|
0
|
|
|
0
|
1
|
0
|
$domain_cache = {}; return; |
|
0
|
|
|
|
|
0
|
|
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub loc { |
143
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; return $self->localizer( $self->locale, @_ ); |
|
0
|
|
|
|
|
0
|
|
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub localize { |
147
|
18
|
|
|
18
|
1
|
4765
|
my ($self, $key, $args) = @_; |
148
|
|
|
|
|
|
|
|
149
|
18
|
50
|
50
|
|
|
56
|
defined $key or return; $key = "${key}"; chomp $key; $args //= {}; |
|
18
|
|
|
|
|
36
|
|
|
18
|
|
|
|
|
58
|
|
|
18
|
|
|
|
|
48
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Lookup the message using the supplied key from the po file |
152
|
18
|
|
|
|
|
55
|
my $text = $self->$_gettext( $key, $args ); |
153
|
|
|
|
|
|
|
|
154
|
18
|
100
|
66
|
|
|
96
|
if (defined $args->{params} and ref $args->{params} eq 'ARRAY') { |
155
|
12
|
100
|
|
|
|
79
|
0 > index $text, '[_' and return $text; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Expand positional parameters of the form [_<n>] |
158
|
|
|
|
|
|
|
return inflate_placeholders [ '[?]', '[]', $args->{no_quote_bind_values}], |
159
|
4
|
|
|
|
|
13
|
$text, @{ $args->{params} }; |
|
4
|
|
|
|
|
20
|
|
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
6
|
50
|
|
|
|
32
|
0 > index $text, '{' and return $text; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Expand named parameters of the form {param_name} |
165
|
0
|
|
|
|
|
0
|
my %args = %{ $args }; my $re = join '|', map { quotemeta $_ } keys %args; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
166
|
|
|
|
|
|
|
|
167
|
0
|
0
|
|
|
|
0
|
$text =~ s{ \{($re)\} }{ defined $args{ $1 } ? $args{ $1 } : "{${1}?}" }egmx; |
|
0
|
|
|
|
|
0
|
|
168
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
0
|
return $text; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub localizer { |
173
|
7
|
|
|
7
|
1
|
1753
|
my ($self, $locale, $key, @args) = @_; my $car = $args[ 0 ]; |
|
7
|
|
|
|
|
13
|
|
174
|
|
|
|
|
|
|
|
175
|
7
|
100
|
|
|
|
25
|
my $args = (is_hashref $car) ? { %{ $car } } |
|
1
|
100
|
|
|
|
3
|
|
176
|
|
|
|
|
|
|
: { params => (is_arrayref $car) ? $car : [ @args ] }; |
177
|
|
|
|
|
|
|
|
178
|
7
|
|
33
|
|
|
39
|
$args->{locale } //= $locale; |
179
|
7
|
|
50
|
|
|
39
|
$args->{no_quote_bind_values} //= TRUE; |
180
|
|
|
|
|
|
|
|
181
|
7
|
|
|
|
|
18
|
return $self->localize( $key, $args ); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
1; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
__END__ |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=pod |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=head1 Name |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Class::Usul::L10N - Localise text strings |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head1 Synopsis |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
use Class::Usul::L10N; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
my $l10n = Class::Usul::L10N->new( { |
199
|
|
|
|
|
|
|
localedir => 'path_to_message_catalogs', |
200
|
|
|
|
|
|
|
log => Log::Handler->new, } ); |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
$local_text = $l10n->localize( 'message_to_localize', { |
203
|
|
|
|
|
|
|
domains => [ 'message_file', 'another_message_file' ], |
204
|
|
|
|
|
|
|
locale => 'de_DE', |
205
|
|
|
|
|
|
|
params => { name => 'value', }, } ); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head1 Description |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Localise text strings by looking them up in a GNU Gettext PO message catalogue |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 Configuration and Environment |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
A POSIX locale id has the form |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
<language>_<country>.<charset>@<key>=<value>;... |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
If the C<use_country> attribute is set to true in the constructor call |
218
|
|
|
|
|
|
|
then the language and country are used from C<locale>. By default |
219
|
|
|
|
|
|
|
C<use_country> is false and only the language from the C<locale> |
220
|
|
|
|
|
|
|
attribute is used |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Defines the following attributes; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=over 3 |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=item C<l10n_attributes> |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Hash ref passed to the L<File::Gettext> constructor |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=over 3 |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=item C<_domains> |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
Names of the mo/po files to search for |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=item C<_source_name> |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Either C<po> for Portable Object (the default) or C<mo> for the Machine Object |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=item C<_use_country> |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
See above |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=back |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item C<localedir> |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Base directory to search for mo/po files |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item C<log> |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Optional logging object |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item C<tempdir> |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Directory to use for temporary files |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=back |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head1 Subroutines/Methods |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head2 BUILDARGS |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Monkey with the constructors signature |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=head2 BUILD |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
Finish initialising the object |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=head2 get_po_header |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
$po_header_hash_ref = $l10n->get_po_header( { locale => 'de' } ); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Returns a hash ref containing the keys and values of the PO header record |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head2 invalidate_cache |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
$l10n->invalidate_cache; |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Causes a reload of the domain files the next time a message is localised |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=head2 loc |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
$local_text = $l10n->loc( $key, @args ); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Calls L</localizer> supplying L</locale> as the first argument |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head2 localize |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
$local_text = $l10n->localize( $key, $args ); |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Localises the message indexed by C<$key>. The message catalogue is |
293
|
|
|
|
|
|
|
loaded from a GNU Gettext portable object file. Returns the C<$key> if |
294
|
|
|
|
|
|
|
the message is not in the catalogue (and C<< $args->{no_default} >> is |
295
|
|
|
|
|
|
|
not true). Language is selected by the C<< $args->{locale} >> |
296
|
|
|
|
|
|
|
attribute. Expands positional parameters of the form C<< [_<n>] >> if |
297
|
|
|
|
|
|
|
C<< $args->{params} >> is an array reference of values to |
298
|
|
|
|
|
|
|
substitute. Otherwise expands named attributes of the form |
299
|
|
|
|
|
|
|
C<< {attr_name} >> using the C<$args> hash for substitution values. If |
300
|
|
|
|
|
|
|
C<< $args->{quote_bind_values} >> is true the placeholder values are |
301
|
|
|
|
|
|
|
displayed wrapped in quotes. The attribute C<< $args->{count} >> is |
302
|
|
|
|
|
|
|
passed to the portable object files plural function which is used to |
303
|
|
|
|
|
|
|
select either the singular or plural form of the translation. If |
304
|
|
|
|
|
|
|
C<< $args->{context} >> is supplied it is prepended to the C<$key> before |
305
|
|
|
|
|
|
|
the lookup in the catalogue takes place |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head2 localizer |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
$local_text = $l10n->localizer( $locale, $key, @args ); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Curries the call to L<localize>. It constructs the C<$args> parameter in the |
312
|
|
|
|
|
|
|
call to L<localize> from the C<@args> parameter, defaulting the C<locale> |
313
|
|
|
|
|
|
|
attribute to C<$locale>. The C<@args> parameter can be a hash reference, |
314
|
|
|
|
|
|
|
an array reference or a list of values |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 Diagnostics |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Asserts that the I<locale> attribute is set |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head1 Dependencies |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=over 3 |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item L<Class::Usul::Constants> |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=item L<Class::Usul::Functions> |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item L<File::DataClass::Types> |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item L<File::Gettext> |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=item L<File::Gettext::Constants> |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=item L<Moo> |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=item L<Try::Tiny> |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=back |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=head1 Incompatibilities |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
There are no known incompatibilities in this module |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head1 Bugs and Limitations |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
There are no known bugs in this module. |
347
|
|
|
|
|
|
|
Please report problems to the address below. |
348
|
|
|
|
|
|
|
Patches are welcome |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head1 Author |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Peter Flanigan, C<< <pjfl@cpan.org> >> |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=head1 Acknowledgements |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Larry Wall - For the Perl programming language |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head1 License and Copyright |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Copyright (c) 2017 Peter Flanigan. All rights reserved |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
363
|
|
|
|
|
|
|
under the same terms as Perl itself. See L<perlartistic> |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
366
|
|
|
|
|
|
|
but WITHOUT WARRANTY; without even the implied warranty of |
367
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
# Local Variables: |
372
|
|
|
|
|
|
|
# mode: perl |
373
|
|
|
|
|
|
|
# tab-width: 3 |
374
|
|
|
|
|
|
|
# End: |