line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## PO Files Manipulation - ~/lib/Text/PO/Gettext.pm |
3
|
|
|
|
|
|
|
## Version v0.3.0 |
4
|
|
|
|
|
|
|
## Copyright(c) 2022 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2021/07/12 |
7
|
|
|
|
|
|
|
## Modified 2023/01/04 |
8
|
|
|
|
|
|
|
## All rights reserved |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
11
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
12
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
13
|
|
|
|
|
|
|
package Text::PO::Gettext; |
14
|
|
|
|
|
|
|
BEGIN |
15
|
|
|
|
|
|
|
{ |
16
|
2
|
|
|
2
|
|
18119678
|
use strict; |
|
2
|
|
|
|
|
13
|
|
|
2
|
|
|
|
|
62
|
|
17
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
52
|
|
18
|
2
|
|
|
2
|
|
10
|
use warnings::register; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
220
|
|
19
|
2
|
|
|
2
|
|
11
|
use parent qw( Module::Generic ); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
11
|
|
20
|
2
|
|
|
2
|
|
122
|
use vars qw( $VERSION $L10N $DOMAIN_RE $LOCALE_RE ); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
121
|
|
21
|
2
|
|
|
2
|
|
458
|
use I18N::Langinfo qw( langinfo ); |
|
2
|
|
|
|
|
722
|
|
|
2
|
|
|
|
|
127
|
|
22
|
2
|
|
|
2
|
|
12
|
use POSIX (); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
31
|
|
23
|
2
|
|
|
2
|
|
552
|
use Text::PO; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
17
|
|
24
|
|
|
|
|
|
|
# l10n_id => lang => string => local string |
25
|
2
|
|
|
2
|
|
860
|
our $L10N = {}; |
26
|
2
|
|
|
|
|
10
|
our $DOMAIN_RE = qr/^[a-z]+(\.[a-zA-Z0-9\_\-]+)*$/; |
27
|
2
|
|
|
|
|
7
|
our $LOCALE_RE = qr/^ |
28
|
|
|
|
|
|
|
(?<locale> |
29
|
|
|
|
|
|
|
(?<locale_lang> |
30
|
|
|
|
|
|
|
[a-z]{2} |
31
|
|
|
|
|
|
|
) |
32
|
|
|
|
|
|
|
(?: |
33
|
|
|
|
|
|
|
[_-](?<locale_country>[A-Z]{2}) |
34
|
|
|
|
|
|
|
)? |
35
|
|
|
|
|
|
|
(?:\.(?<locale_encoding>[\w-]+))? |
36
|
|
|
|
|
|
|
) |
37
|
|
|
|
|
|
|
$/x; |
38
|
2
|
|
|
|
|
40
|
our $VERSION = 'v0.3.0'; |
39
|
|
|
|
|
|
|
}; |
40
|
|
|
|
|
|
|
|
41
|
2
|
|
|
2
|
|
12
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
37
|
|
42
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
1289
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub init |
45
|
|
|
|
|
|
|
{ |
46
|
2
|
|
|
2
|
1
|
3546763
|
my $self = shift( @_ ); |
47
|
2
|
|
|
|
|
98
|
$self->{category} = 'LC_MESSAGES'; |
48
|
2
|
|
|
|
|
23
|
$self->{domain} = ''; |
49
|
|
|
|
|
|
|
# We also try LANGUAGE because GNU gettext actually only recognise LANGUAGE |
50
|
|
|
|
|
|
|
# For example: LANGUAGE=fr_FR.utf-8 TEXTDOMAINDIR=./t gettext -d "com.example.api" -s "Bad Request" |
51
|
2
|
|
33
|
|
|
53
|
$self->{locale} = $ENV{LANG} || $ENV{LANGUAGE}; |
52
|
2
|
|
|
|
|
27
|
$self->{path} = ''; |
53
|
2
|
|
|
|
|
18
|
$self->{plural} = []; |
54
|
2
|
|
|
|
|
19
|
$self->{use_json} = 1; |
55
|
2
|
|
|
|
|
15
|
$self->{_init_strict_use_sub} = 1; |
56
|
2
|
|
|
|
|
47
|
$self->{_init_params_order} = [qw( category path domain locale plural use_json )]; |
57
|
2
|
50
|
|
|
|
45
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
58
|
2
|
50
|
33
|
|
|
421
|
if( !defined( $self->{path} ) || !length( $self->{path} ) ) |
59
|
|
|
|
|
|
|
{ |
60
|
0
|
|
|
|
|
0
|
return( $self->error( "No directory path was provided for localisation" ) ); |
61
|
|
|
|
|
|
|
} |
62
|
2
|
50
|
|
|
|
65
|
$self->textdomain( $self->{domain} ) || return( $self->pass_error ); |
63
|
2
|
|
|
|
|
6716
|
return( $self ); |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub addItem |
67
|
|
|
|
|
|
|
{ |
68
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
69
|
0
|
|
|
|
|
0
|
my( $locale, $key, $value ) = @_; |
70
|
0
|
|
|
|
|
0
|
my $hash = $self->getDomainHash(); |
71
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "No locale was provided." ) ) if( !defined( $locale ) || !length( $locale ) ); |
72
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "No msgid was provided." ) ) if( !defined( $key ) || !length( $key ) ); |
73
|
0
|
|
|
|
|
0
|
$locale = $self->locale_unix( $locale ); |
74
|
0
|
0
|
|
|
|
0
|
if( !$self->isSupportedLanguage( $locale ) ) |
75
|
|
|
|
|
|
|
{ |
76
|
0
|
|
|
|
|
0
|
return( $self->error( "Language requested \"${locale}\" to add item is not supported." ) ); |
77
|
|
|
|
|
|
|
} |
78
|
0
|
|
|
|
|
0
|
$hash->{ $locale }->{ $key } = { msgid => $key, msgstr => $value }; |
79
|
0
|
|
|
|
|
0
|
return( $hash->{ $locale }->{ $key } ); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
12
|
|
|
12
|
1
|
1464
|
sub category { return( shift->_set_get_scalar_as_object( 'category', @_ ) ); } |
83
|
|
|
|
|
|
|
|
84
|
1
|
|
|
1
|
1
|
1603
|
sub charset { return( shift->_get_po->charset ); } |
85
|
|
|
|
|
|
|
|
86
|
1
|
|
|
1
|
1
|
1206
|
sub contentEncoding { return( shift->_get_po->content_encoding ); } |
87
|
|
|
|
|
|
|
|
88
|
1
|
|
|
1
|
1
|
5
|
sub contentType { return( shift->_get_po->content_type ); } |
89
|
|
|
|
|
|
|
|
90
|
1
|
|
|
1
|
1
|
11
|
sub currentLang { return( shift->_get_po->current_lang ); } |
91
|
|
|
|
|
|
|
|
92
|
1
|
|
|
1
|
1
|
810
|
sub dgettext { return( shift->dngettext( @_ ) ); } |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub dngettext |
95
|
|
|
|
|
|
|
{ |
96
|
14
|
|
|
14
|
1
|
4155
|
my $self = shift( @_ ); |
97
|
14
|
|
|
|
|
47
|
my $opts = {}; |
98
|
14
|
100
|
|
|
|
70
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
99
|
14
|
|
|
|
|
43
|
my( $domain, $msgid, $msgidPlural, $count ) = @_; |
100
|
14
|
|
|
|
|
36
|
my $default; |
101
|
|
|
|
|
|
|
my $index; |
102
|
14
|
100
|
66
|
|
|
98
|
if( !defined( $count ) || $count !~ /^\d+$/ ) |
103
|
|
|
|
|
|
|
{ |
104
|
10
|
|
33
|
|
|
47
|
$default = $msgidPlural || $msgid; |
105
|
|
|
|
|
|
|
} |
106
|
14
|
100
|
100
|
|
|
91
|
if( !exists( $opts->{locale} ) || !length( $opts->{locale} ) ) |
107
|
|
|
|
|
|
|
{ |
108
|
7
|
|
|
|
|
21
|
$opts->{locale} = $self->locale; |
109
|
|
|
|
|
|
|
} |
110
|
14
|
|
|
|
|
1340
|
my $hash = $self->getDomainHash({ domain => $domain }); |
111
|
14
|
|
|
|
|
64
|
my $plural = $self->plural; |
112
|
14
|
50
|
|
|
|
1934
|
if( !exists( $hash->{ $opts->{locale} } ) ) |
113
|
|
|
|
|
|
|
{ |
114
|
0
|
0
|
|
|
|
0
|
warnings::warn( "No locale \"$opts->{locale}\" found for the domain \"${domain}\".\n" ) if( warnings::enabled() ); |
115
|
0
|
|
|
|
|
0
|
return( Text::PO::String->new( $default ) ); |
116
|
|
|
|
|
|
|
} |
117
|
14
|
|
|
|
|
86
|
my $l10n = $hash->{ $opts->{locale} }; |
118
|
14
|
|
|
|
|
60
|
my $dict = $l10n->{ $msgid }; |
119
|
14
|
50
|
|
|
|
35
|
if( $dict ) |
120
|
|
|
|
|
|
|
{ |
121
|
14
|
50
|
|
|
|
68
|
if( $plural->length == 0 ) |
122
|
|
|
|
|
|
|
{ |
123
|
0
|
|
|
|
|
0
|
$plural = $self->getPlural(); |
124
|
|
|
|
|
|
|
} |
125
|
14
|
100
|
|
|
|
130290
|
if( ref( $dict->{msgstr} ) eq 'ARRAY' ) |
126
|
|
|
|
|
|
|
{ |
127
|
4
|
50
|
33
|
|
|
573
|
if( $self->_is_number( $count ) && |
128
|
|
|
|
|
|
|
int( $plural->[0] ) > 0 ) |
129
|
|
|
|
|
|
|
{ |
130
|
2
|
|
|
2
|
|
16
|
no warnings 'once'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
6619
|
|
131
|
4
|
|
|
|
|
1130
|
my $n = $count; |
132
|
4
|
|
|
|
|
14
|
my $expr = $plural->[1]; |
133
|
4
|
|
|
|
|
41
|
$expr =~ s/(?:^|\b)(?<!\$)(n)(?:\b|$)/\$$1/g; |
134
|
4
|
|
|
|
|
271
|
$index = eval( $expr ); |
135
|
4
|
|
|
|
|
18
|
$index = int( $index ); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
else |
138
|
|
|
|
|
|
|
{ |
139
|
0
|
|
|
|
|
0
|
$index = 0; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
# return( join( '', @{$dict->{msgstr}->[ $index ]} ) || $default ); |
142
|
4
|
|
|
|
|
47
|
my $locale_str = join( '', @{$dict->{msgstr}->[ $index ]} ); |
|
4
|
|
|
|
|
59
|
|
143
|
4
|
50
|
|
|
|
68
|
return( Text::PO::String->new( $locale_str => $opts->{locale} ) ) if( length( "$locale_str" ) ); |
144
|
0
|
|
|
|
|
0
|
return( Text::PO::String->new( $default ) ); |
145
|
|
|
|
|
|
|
} |
146
|
10
|
|
33
|
|
|
1439
|
return( $dict->{msgstr} || $default ); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
else |
149
|
|
|
|
|
|
|
{ |
150
|
0
|
0
|
|
|
|
0
|
warnings::warn( "No dictionary was found for msgid \"${msgid}\" and domain \"${domain}\"" ) if( warnings::enabled() ); |
151
|
|
|
|
|
|
|
} |
152
|
0
|
|
|
|
|
0
|
return( $default ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub domain |
156
|
|
|
|
|
|
|
{ |
157
|
40
|
|
|
40
|
1
|
1420
|
my $self = shift( @_ ); |
158
|
40
|
100
|
|
|
|
148
|
if( @_ ) |
159
|
|
|
|
|
|
|
{ |
160
|
2
|
|
|
|
|
21
|
my $v = shift( @_ ); |
161
|
2
|
50
|
|
|
|
104
|
if( !$v ) |
|
|
50
|
|
|
|
|
|
162
|
|
|
|
|
|
|
{ |
163
|
0
|
|
|
|
|
0
|
return( $self->error( "No domain was provided." ) ); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
elsif( $v !~ /^$DOMAIN_RE$/ ) |
166
|
|
|
|
|
|
|
{ |
167
|
0
|
|
|
|
|
0
|
return( $self->error( "Domain provided \"$v\" contains illegal characters." ) ); |
168
|
|
|
|
|
|
|
} |
169
|
2
|
|
|
|
|
64
|
my $caller = [caller(1)]->[3]; |
170
|
|
|
|
|
|
|
# We do not call textdomain upon init, because we need both domain and locale to be set first |
171
|
|
|
|
|
|
|
# textdomain() is called directly in init() |
172
|
2
|
50
|
|
|
|
21
|
$self->textdomain( $v ) unless( $caller eq 'Module::Generic::init' ); |
173
|
2
|
|
|
|
|
14
|
$self->{domain} = $v; |
174
|
|
|
|
|
|
|
} |
175
|
40
|
|
|
|
|
143
|
return( $self->_set_get_scalar_as_object( 'domain' ) ); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub exists |
179
|
|
|
|
|
|
|
{ |
180
|
2
|
|
|
2
|
1
|
2596
|
my $self = shift( @_ ); |
181
|
2
|
|
|
|
|
13
|
my $lang = shift( @_ ); |
182
|
2
|
50
|
|
|
|
188
|
if( !defined( $lang ) ) |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
183
|
|
|
|
|
|
|
{ |
184
|
0
|
|
|
|
|
0
|
return( $self->error( "No language to check for existence was provided." ) ); |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
elsif( !length( $lang ) ) |
187
|
|
|
|
|
|
|
{ |
188
|
0
|
|
|
|
|
0
|
return( $self->error( "Language provided to check for existence is null." ) ); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
elsif( $lang !~ /^$LOCALE_RE$/ ) |
191
|
|
|
|
|
|
|
{ |
192
|
0
|
|
|
|
|
0
|
return( $self->error( "Unsupported locale format \"${lang}\"." ) ); |
193
|
|
|
|
|
|
|
} |
194
|
2
|
|
|
|
|
29
|
$lang = $self->locale_unix( $lang ); |
195
|
2
|
|
|
|
|
24
|
my $hash = $self->getDomainHash(); |
196
|
2
|
|
|
|
|
28
|
return( exists( $hash->{ $lang } ) ); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub fetchLocale |
200
|
|
|
|
|
|
|
{ |
201
|
3
|
|
|
3
|
1
|
24
|
my $self = shift( @_ ); |
202
|
3
|
|
|
|
|
21
|
my $key = shift( @_ ); |
203
|
3
|
|
|
|
|
23
|
my $hash = $self->getDomainHash(); |
204
|
3
|
|
|
|
|
23
|
my $spans = []; |
205
|
|
|
|
|
|
|
# Browsing through each available locale language |
206
|
|
|
|
|
|
|
# Make it predictable using sort() |
207
|
3
|
|
|
|
|
40
|
foreach my $k ( sort( keys( %$hash ) ) ) |
208
|
|
|
|
|
|
|
{ |
209
|
6
|
|
|
|
|
39
|
my $locWeb = $self->locale_web( $k ); |
210
|
6
|
|
|
|
|
40
|
push( @$spans, "<span lang=\"${locWeb}\">" . $self->dngettext( $self->domain, $key, { locale => $k }) . '</span>' ); |
211
|
|
|
|
|
|
|
} |
212
|
3
|
|
|
|
|
26
|
return( $self->new_array( $spans ) ); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
2
|
|
|
2
|
1
|
55137
|
sub getDataPath { return( $ENV{TEXTDOMAINDIR} ); } |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub getDaysLong |
218
|
|
|
|
|
|
|
{ |
219
|
2
|
|
|
2
|
1
|
23036
|
my $self = shift( @_ ); |
220
|
2
|
|
|
|
|
8
|
my $opts = $self->_get_args_as_hash( @_ ); |
221
|
2
|
|
|
|
|
179
|
my $ref = $self->_get_days( $self->locale ); |
222
|
2
|
|
|
|
|
6
|
my $days = $ref->[1]; |
223
|
2
|
100
|
|
|
|
9
|
if( $opts->{monday_first} ) |
224
|
|
|
|
|
|
|
{ |
225
|
|
|
|
|
|
|
# Move Sunday at the end |
226
|
1
|
|
|
|
|
3
|
push( @$days, shift( @$days ) ); |
227
|
|
|
|
|
|
|
} |
228
|
2
|
|
|
|
|
10
|
return( $days ); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub getDaysShort |
232
|
|
|
|
|
|
|
{ |
233
|
2
|
|
|
2
|
1
|
22916
|
my $self = shift( @_ ); |
234
|
2
|
|
|
|
|
10
|
my $opts = $self->_get_args_as_hash( @_ ); |
235
|
2
|
|
|
|
|
134
|
my $ref = $self->_get_days( $self->locale ); |
236
|
2
|
|
|
|
|
9
|
my $days = $ref->[0]; |
237
|
2
|
100
|
|
|
|
9
|
if( $opts->{monday_first} ) |
238
|
|
|
|
|
|
|
{ |
239
|
|
|
|
|
|
|
# Move Sunday at the end |
240
|
1
|
|
|
|
|
3
|
push( @$days, shift( @$days ) ); |
241
|
|
|
|
|
|
|
} |
242
|
2
|
|
|
|
|
9
|
return( $days ); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub getDomainHash |
246
|
|
|
|
|
|
|
{ |
247
|
38
|
|
|
38
|
1
|
5323
|
my $self = shift( @_ ); |
248
|
38
|
|
|
|
|
145
|
my $opts = $self->_get_args_as_hash( @_ ); |
249
|
38
|
|
66
|
|
|
3791
|
$opts->{domain} //= $self->domain; |
250
|
|
|
|
|
|
|
|
251
|
38
|
|
|
|
|
4442
|
my $hash = $L10N; |
252
|
38
|
50
|
|
|
|
121
|
if( !exists( $hash->{ $opts->{domain} } ) ) |
253
|
|
|
|
|
|
|
{ |
254
|
0
|
|
|
|
|
0
|
retrn( $self->error( "No locale data for domain \"$opts->{domain}\"." ) ); |
255
|
|
|
|
|
|
|
} |
256
|
38
|
|
|
|
|
287
|
my $l10n = $hash->{ $opts->{domain} }; |
257
|
38
|
100
|
66
|
|
|
457
|
if( exists( $opts->{locale} ) && |
258
|
|
|
|
|
|
|
defined( $opts->{locale} ) ) |
259
|
|
|
|
|
|
|
{ |
260
|
18
|
|
|
|
|
89
|
$opts->{locale} = $self->locale_unix( $opts->{locale} ); |
261
|
18
|
50
|
|
|
|
64
|
if( length( $opts->{locale} ) == 0 ) |
262
|
|
|
|
|
|
|
{ |
263
|
0
|
|
|
|
|
0
|
return( $self->error( "Locale was provided, but is empty." ) ); |
264
|
|
|
|
|
|
|
} |
265
|
18
|
|
|
|
|
68
|
return( $l10n->{ $opts->{locale} } ); |
266
|
|
|
|
|
|
|
} |
267
|
20
|
|
|
|
|
67
|
return( $l10n ); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
2
|
|
|
2
|
1
|
44217
|
sub getLangDataPath { return( $ENV{TEXTLOCALEDIR} ); } |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub getLanguageDict |
273
|
|
|
|
|
|
|
{ |
274
|
2
|
|
|
2
|
1
|
2577
|
my $self = shift( @_ ); |
275
|
2
|
|
50
|
|
|
28
|
my $lang = shift( @_ ) || return( $self->error( "Language provided, to get its dictionary, is undefined or null." ) ); |
276
|
2
|
50
|
|
|
|
219
|
if( $lang !~ /^$LOCALE_RE$/ ) |
277
|
|
|
|
|
|
|
{ |
278
|
0
|
|
|
|
|
0
|
return( $self->error( "Locale provided (${lang}) is in an unsupported format." ) ); |
279
|
|
|
|
|
|
|
} |
280
|
2
|
|
|
|
|
36
|
$lang = $self->locale_unix( $lang ); |
281
|
|
|
|
|
|
|
|
282
|
2
|
100
|
|
|
|
22
|
if( !$self->isSupportedLanguage( $lang ) ) |
283
|
|
|
|
|
|
|
{ |
284
|
1
|
|
|
|
|
51
|
return( $self->error( "Language provided (${lang}), to get its dictionary, is unsupported." ) ); |
285
|
|
|
|
|
|
|
} |
286
|
1
|
|
|
|
|
18
|
my $hash = $self->getDomainHash(); |
287
|
1
|
50
|
|
|
|
16
|
if( !exists( $hash->{ $lang } ) ) |
288
|
|
|
|
|
|
|
{ |
289
|
0
|
|
|
|
|
0
|
return( $self->error( "Language provided (${lang}), to get its dictionary, could not be found. This is weird. Most likely a configuration mistake." ) ); |
290
|
|
|
|
|
|
|
} |
291
|
1
|
|
|
|
|
10
|
return( $hash->{ $lang } ); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
1
|
|
|
1
|
1
|
11836
|
sub getLocale { return( shift->locale ); } |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub getLocales |
297
|
|
|
|
|
|
|
{ |
298
|
1
|
|
|
1
|
1
|
1207
|
my $self = shift( @_ ); |
299
|
1
|
|
50
|
|
|
16
|
my $key = shift( @_ ) || return( $self->error( "No text provided to get its localised equivalent" ) ); |
300
|
1
|
|
50
|
|
|
15
|
my $res = $self->fetchLocale( $key ) || return( $self->pass_error ); |
301
|
1
|
50
|
|
|
|
38
|
if( scalar( @$res ) > 0 ) |
302
|
|
|
|
|
|
|
{ |
303
|
1
|
|
|
|
|
14
|
return( join( "\n", @$res ) ); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
else |
306
|
|
|
|
|
|
|
{ |
307
|
0
|
|
|
|
|
0
|
return( $key ); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub getLocalesf |
312
|
|
|
|
|
|
|
{ |
313
|
1
|
|
|
1
|
1
|
842
|
my $self = shift( @_ ); |
314
|
1
|
|
50
|
|
|
23
|
my $key = shift( @_ ) || return( $self->error( "No text provided to get its localised equivalent" ) ); |
315
|
1
|
|
50
|
|
|
15
|
my $res = $self->fetchLocale( $key ) || return( $self->pass_error ); |
316
|
1
|
50
|
|
|
|
51
|
if( scalar( @$res ) > 0 ) |
317
|
|
|
|
|
|
|
{ |
318
|
1
|
|
|
|
|
17
|
for( my $i = 0; $i < scalar( @$res ); $i++ ) |
319
|
|
|
|
|
|
|
{ |
320
|
2
|
|
|
|
|
26
|
$res->[$i] = sprintf( $res->[$i], @_ ); |
321
|
|
|
|
|
|
|
} |
322
|
1
|
|
|
|
|
13
|
return( join( "\n", @$res ) ); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
else |
325
|
|
|
|
|
|
|
{ |
326
|
0
|
|
|
|
|
0
|
return( sprintf( $key, @_ ) ); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub getMetaKeys |
331
|
|
|
|
|
|
|
{ |
332
|
1
|
|
|
1
|
1
|
849
|
my $self = shift( @_ ); |
333
|
1
|
|
|
|
|
10
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
334
|
1
|
|
50
|
|
|
28
|
my $po = $hash->{_po} || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
335
|
1
|
|
|
|
|
22
|
return( $po->meta_keys ); |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub getMetaValue |
339
|
|
|
|
|
|
|
{ |
340
|
1
|
|
|
1
|
1
|
11209
|
my $self = shift( @_ ); |
341
|
1
|
|
50
|
|
|
82
|
my $field = shift( @_ ) || return( $self->error( "No meta field provided to get its value." ) ); |
342
|
1
|
|
|
|
|
16
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
343
|
1
|
|
50
|
|
|
23
|
my $po = $hash->{_po} || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
344
|
1
|
|
|
|
|
15
|
return( $po->meta( $field ) ); |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub getMonthsLong |
348
|
|
|
|
|
|
|
{ |
349
|
1
|
|
|
1
|
1
|
335
|
my $self = shift( @_ ); |
350
|
1
|
|
|
|
|
4
|
my $ref = $self->_get_months( $self->locale ); |
351
|
1
|
|
|
|
|
7
|
return( $ref->[1] ); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub getMonthsShort |
355
|
|
|
|
|
|
|
{ |
356
|
1
|
|
|
1
|
1
|
12049
|
my $self = shift( @_ ); |
357
|
1
|
|
|
|
|
5
|
my $ref = $self->_get_months( $self->locale ); |
358
|
1
|
|
|
|
|
6
|
return( $ref->[0] ); |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub getNumericDict |
362
|
|
|
|
|
|
|
{ |
363
|
1
|
|
|
1
|
1
|
11436
|
my $self = shift( @_ ); |
364
|
1
|
|
|
|
|
6
|
my $ref = $self->_get_numeric_dict( $self->locale ); |
365
|
1
|
|
|
|
|
16
|
return( $ref->[0] ); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub getNumericPosixDict |
369
|
|
|
|
|
|
|
{ |
370
|
1
|
|
|
1
|
1
|
4530
|
my $self = shift( @_ ); |
371
|
1
|
|
|
|
|
5
|
my $ref = $self->_get_numeric_dict( $self->locale ); |
372
|
1
|
|
|
|
|
14
|
return( $ref->[1] ); |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub getPlural |
376
|
|
|
|
|
|
|
{ |
377
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
378
|
1
|
|
50
|
|
|
9
|
my $po = $self->_get_po || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
379
|
1
|
|
|
|
|
22
|
return( $po->plural ); |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub getText |
383
|
|
|
|
|
|
|
{ |
384
|
2
|
|
|
2
|
1
|
849
|
my $self = shift( @_ ); |
385
|
2
|
|
|
|
|
20
|
my( $key, $lang ) = @_; |
386
|
2
|
50
|
33
|
|
|
38
|
return( $self->error( "No text to get its localised equivalent was provided." ) ) if( !defined( $key ) || !length( $key ) ); |
387
|
2
|
|
|
|
|
14
|
return( $self->dngettext( $self->domain, $key, { locale => $lang }) ); |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub getTextf |
391
|
|
|
|
|
|
|
{ |
392
|
1
|
|
|
1
|
1
|
10
|
my $self = shift( @_ ); |
393
|
1
|
|
|
|
|
10
|
my $opts = {}; |
394
|
1
|
50
|
|
|
|
7
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
395
|
1
|
|
33
|
|
|
9
|
$opts->{lang} = $self->locale || $self->currentLang(); |
396
|
1
|
|
|
|
|
214
|
my $key = shift( @_ ); |
397
|
1
|
|
|
|
|
13
|
my $text = $self->getText( $key, $opts->{lang} ); |
398
|
1
|
|
|
|
|
26
|
return( sprintf( $text, @_ ) ); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub gettext |
402
|
|
|
|
|
|
|
{ |
403
|
1
|
|
|
1
|
1
|
11
|
my $self = shift( @_ ); |
404
|
1
|
|
|
|
|
6
|
return( $self->dngettext( $self->domain, shift( @_ ) ) ); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
0
|
|
|
0
|
1
|
0
|
sub gettextf { return( shift->getTextf( @_ ) ); } |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub isSupportedLanguage |
410
|
|
|
|
|
|
|
{ |
411
|
3
|
|
|
3
|
1
|
20
|
my $self = shift( @_ ); |
412
|
3
|
|
50
|
|
|
25
|
my $lang = shift( @_ ) || return(0); |
413
|
3
|
|
|
|
|
28
|
$lang = $self->locale_unix( $lang ); |
414
|
3
|
|
|
|
|
31
|
my $dom = $self->domain; |
415
|
3
|
50
|
|
|
|
619
|
return( $self->error( "No domain \"$dom\" set!" ) ) if( !CORE::exists( $L10N->{ $dom } ) ); |
416
|
3
|
|
|
|
|
38
|
my $dict = $L10N->{ $dom }; |
417
|
3
|
100
|
|
|
|
39
|
if( CORE::exists( $dict->{ $lang } ) ) |
418
|
|
|
|
|
|
|
{ |
419
|
2
|
|
|
|
|
28
|
return(1); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
else |
422
|
|
|
|
|
|
|
{ |
423
|
1
|
|
|
|
|
10
|
return(0); |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
|
427
|
1
|
|
|
1
|
1
|
15
|
sub language { return( shift->_get_po->language ); } |
428
|
|
|
|
|
|
|
|
429
|
1
|
|
|
1
|
1
|
848
|
sub languageTeam { return( shift->_get_po->language_team ); } |
430
|
|
|
|
|
|
|
|
431
|
1
|
|
|
1
|
1
|
851
|
sub lastTranslator { return( shift->_get_po->last_translator ); } |
432
|
|
|
|
|
|
|
|
433
|
1
|
|
|
1
|
1
|
892
|
sub mimeVersion { return( shift->_get_po->mime_version ); } |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub locale |
436
|
|
|
|
|
|
|
{ |
437
|
41
|
|
|
41
|
1
|
14038
|
my $self = shift( @_ ); |
438
|
41
|
100
|
|
|
|
152
|
if( @_ ) |
439
|
|
|
|
|
|
|
{ |
440
|
2
|
|
|
|
|
14
|
my $v = shift( @_ ); |
441
|
2
|
50
|
33
|
|
|
198
|
if( !defined( $v ) || !length( $v ) ) |
|
|
50
|
|
|
|
|
|
442
|
|
|
|
|
|
|
{ |
443
|
0
|
|
|
|
|
0
|
return( $self->error( "No language was set." ) ); |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
elsif( $v =~ /^$LOCALE_RE$/ ) |
446
|
|
|
|
|
|
|
{ |
447
|
2
|
50
|
|
|
|
61
|
$v = join( '_', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
448
|
2
|
50
|
|
|
|
34
|
$v .= '.' . $+{locale_encoding} if( $+{locale_encoding} ); |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
else |
451
|
|
|
|
|
|
|
{ |
452
|
0
|
|
|
|
|
0
|
return( $self->error( "Language provided (\"$v\") is in an unsupported format. Use something like \"en_GB\", \"en-GB\" or simply \"en\" or even \"en_GB.utf-8\"." ) ); |
453
|
|
|
|
|
|
|
} |
454
|
2
|
50
|
|
|
|
22
|
return( $self->error( "No domain is set or it has disappeared!" ) ) if( !$self->{domain} ); |
455
|
2
|
|
|
|
|
45
|
$self->{locale} = $v; |
456
|
2
|
|
|
|
|
45
|
my $caller = [caller(1)]->[3]; |
457
|
|
|
|
|
|
|
# We do not call textdomain upon init, because we need both domain and locale to be set first |
458
|
|
|
|
|
|
|
# textdomain() is called directly in init() |
459
|
2
|
50
|
|
|
|
20
|
$self->textdomain( $self->{domain} ) unless( $caller eq 'Module::Generic::init' ); |
460
|
|
|
|
|
|
|
} |
461
|
41
|
|
|
|
|
152
|
return( $self->_set_get_scalar_as_object( 'locale' ) ); |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub locale_unix |
465
|
|
|
|
|
|
|
{ |
466
|
31
|
|
|
31
|
1
|
1048
|
my $self = shift( @_ ); |
467
|
31
|
|
66
|
|
|
147
|
my $loc = shift( @_ ) || $self->locale; |
468
|
|
|
|
|
|
|
# Only once |
469
|
31
|
50
|
|
|
|
848
|
if( $loc =~ /^$LOCALE_RE$/ ) |
470
|
|
|
|
|
|
|
{ |
471
|
31
|
100
|
|
|
|
630
|
$loc = join( '_', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
472
|
31
|
100
|
|
|
|
208
|
$loc .= '.' . $+{locale_encoding} if( $+{locale_encoding} ); |
473
|
|
|
|
|
|
|
} |
474
|
31
|
|
|
|
|
171
|
return( $loc ); |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub locale_web |
478
|
|
|
|
|
|
|
{ |
479
|
10
|
|
|
10
|
1
|
33
|
my $self = shift( @_ ); |
480
|
10
|
|
33
|
|
|
62
|
my $loc = shift( @_ ) || $self->locale; |
481
|
|
|
|
|
|
|
# Only once |
482
|
10
|
50
|
|
|
|
288
|
if( $loc =~ /^$LOCALE_RE$/ ) |
483
|
|
|
|
|
|
|
{ |
484
|
10
|
100
|
|
|
|
155
|
$loc = join( '-', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
485
|
10
|
100
|
|
|
|
92
|
$loc .= '.' . $+{locale_encoding} if( $+{locale_encoding} ); |
486
|
|
|
|
|
|
|
} |
487
|
10
|
|
|
|
|
67
|
return( $loc ); |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub ngettext |
491
|
|
|
|
|
|
|
{ |
492
|
2
|
|
|
2
|
1
|
718
|
my $self = shift( @_ ); |
493
|
2
|
|
|
|
|
16
|
my( $msgid, $msgidPlural, $count ) = @_; |
494
|
2
|
|
|
|
|
13
|
return( $self->dngettext( $self->domain, $msgid, $msgidPlural, $count ) ); |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
5
|
|
|
5
|
1
|
1360
|
sub path { return( shift->_set_get_file( 'path', @_ ) ); } |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub plural |
500
|
|
|
|
|
|
|
{ |
501
|
15
|
|
|
15
|
1
|
1087
|
my $self = shift( @_ ); |
502
|
15
|
50
|
|
|
|
47
|
if( @_ ) |
503
|
|
|
|
|
|
|
{ |
504
|
0
|
|
|
|
|
0
|
return( $self->_set_get_array_as_object( 'plural', @_ ) ); |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
else |
507
|
|
|
|
|
|
|
{ |
508
|
15
|
100
|
|
|
|
26
|
if( !scalar( @{$self->{plural}} ) ) |
|
15
|
|
|
|
|
61
|
|
509
|
|
|
|
|
|
|
{ |
510
|
1
|
|
|
|
|
14
|
$self->{plural} = $self->getPlural(); |
511
|
|
|
|
|
|
|
} |
512
|
15
|
|
|
|
|
60
|
return( $self->_set_get_array_as_object( 'plural' ) ); |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
1
|
|
|
1
|
1
|
12647
|
sub pluralForms { return( shift->_get_po->plural_forms ); } |
517
|
|
|
|
|
|
|
|
518
|
1
|
|
|
1
|
1
|
869
|
sub po_object { return( shift->_get_po ); } |
519
|
|
|
|
|
|
|
|
520
|
1
|
|
|
1
|
1
|
550
|
sub poRevisionDate { return( shift->_get_po->po_revision_date ); } |
521
|
|
|
|
|
|
|
|
522
|
1
|
|
|
1
|
1
|
2433
|
sub potCreationDate { return( shift->_get_po->pot_creation_date ); } |
523
|
|
|
|
|
|
|
|
524
|
1
|
|
|
1
|
1
|
2001
|
sub projectIdVersion { return( shift->_get_po->project_id_version ); } |
525
|
|
|
|
|
|
|
|
526
|
1
|
|
|
1
|
1
|
826
|
sub reportBugsTo { return( shift->_get_po->report_bugs_to ); } |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
sub textdomain |
529
|
|
|
|
|
|
|
{ |
530
|
2
|
|
|
2
|
1
|
7
|
my $self = shift( @_ ); |
531
|
2
|
|
50
|
|
|
14
|
my $dom = shift( @_ ) || return( $self->error( "No domain was provided." ) ); |
532
|
2
|
|
|
|
|
56
|
my $base = $self->path; |
533
|
2
|
|
|
|
|
270
|
my $lang = $self->locale_unix; |
534
|
2
|
50
|
|
|
|
31
|
my $path_po = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.po" ); |
535
|
2
|
50
|
|
|
|
94299
|
my $path_json = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.json" ); |
536
|
2
|
50
|
|
|
|
90212
|
my $path_mo = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.mo" ); |
537
|
2
|
|
|
|
|
89157
|
my $file; |
538
|
|
|
|
|
|
|
my $po; |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
2
|
50
|
33
|
|
|
97
|
if( $self->use_json && $path_json->exists ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
542
|
|
|
|
|
|
|
{ |
543
|
2
|
|
|
|
|
522
|
$file = $path_json; |
544
|
2
|
|
50
|
|
|
22
|
$po = Text::PO->new( domain => $dom, use_json => 1, debug => $self->debug ) || |
545
|
|
|
|
|
|
|
return( $self->pass_error( Text::PO->error ) ); |
546
|
2
|
50
|
|
|
|
53
|
$po->parse2object( $file ) || |
547
|
|
|
|
|
|
|
return( $self->pass_error( $po->error ) ); |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
elsif( $path_po->exists ) |
550
|
|
|
|
|
|
|
{ |
551
|
0
|
|
|
|
|
0
|
$file = $path_po; |
552
|
0
|
|
0
|
|
|
0
|
$po = Text::PO->new( domain => $dom, debug => $self->debug ) || |
553
|
|
|
|
|
|
|
return( $self->pass_error( Text::PO->error ) ); |
554
|
0
|
0
|
|
|
|
0
|
$po->parse( $file ) || |
555
|
|
|
|
|
|
|
return( $self->pass_error( $po->error ) ); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
elsif( $path_mo->exists ) |
558
|
|
|
|
|
|
|
{ |
559
|
0
|
|
|
|
|
0
|
$file = $path_mo; |
560
|
0
|
|
0
|
|
|
0
|
my $mo = Text::PO::MO->new( $file, { domain => $dom, debug => $self->debug }) || |
561
|
|
|
|
|
|
|
return( $self->pass_error( Text::PO::MO->error ) ); |
562
|
0
|
|
0
|
|
|
0
|
$po = $mo->as_object || |
563
|
|
|
|
|
|
|
return( $self->pass_error( $po->error ) ); |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
else |
566
|
|
|
|
|
|
|
{ |
567
|
0
|
|
|
|
|
0
|
return( $self->error( "No data file could be found for \"$dom\" for either json, po, or mo file." ) ); |
568
|
|
|
|
|
|
|
} |
569
|
2
|
100
|
|
|
|
21
|
$L10N->{ $dom } = {} if( ref( $L10N->{ $dom } ) ne 'HASH' ); |
570
|
2
|
50
|
|
|
|
49
|
my $dict = $L10N->{ $dom }->{ $lang } = {} if( ref( $L10N->{ $dom }->{ $lang } ) ne 'HASH' ); |
571
|
2
|
|
|
|
|
57
|
$dict->{_po} = $po; |
572
|
|
|
|
|
|
|
$po->elements->foreach(sub |
573
|
|
|
|
|
|
|
{ |
574
|
18
|
|
|
18
|
|
835
|
my $ref = shift( @_ ); |
575
|
18
|
|
|
|
|
79
|
$dict->{ $ref->{msgid} } = $ref; |
576
|
2
|
|
|
|
|
24
|
}); |
577
|
2
|
|
|
|
|
91
|
return( $self ); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
3
|
|
|
3
|
1
|
254
|
sub use_json { return( shift->_set_get_boolean( 'use_json', @_ ) ); } |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub _get_days |
583
|
|
|
|
|
|
|
{ |
584
|
4
|
|
|
4
|
|
780
|
my $self = shift( @_ ); |
585
|
4
|
|
|
|
|
9
|
my $locale = shift( @_ ); |
586
|
4
|
|
|
|
|
18
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
587
|
4
|
|
|
|
|
18
|
my $short = $self->new_array; |
588
|
4
|
|
|
|
|
59
|
my $long = $self->new_array; |
589
|
|
|
|
|
|
|
|
590
|
4
|
50
|
|
|
|
64
|
POSIX::setlocale( &POSIX::LC_ALL, $locale ) if( defined( $locale ) ); |
591
|
|
|
|
|
|
|
|
592
|
4
|
|
|
|
|
51
|
for (my $i = 1; $i <= 7; $i++) |
593
|
|
|
|
|
|
|
{ |
594
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::ABDAY_${i}"; |
595
|
28
|
|
|
|
|
133
|
my $const = I18N::Langinfo->can( "ABDAY_${i}" ); |
596
|
|
|
|
|
|
|
# $short->[$i-1] = langinfo( &$const ); |
597
|
28
|
|
|
|
|
130
|
$short->[$i-1] = langinfo( $const->() ); |
598
|
|
|
|
|
|
|
} |
599
|
4
|
|
|
|
|
17
|
for (my $i = 1; $i <= 7; $i++) |
600
|
|
|
|
|
|
|
{ |
601
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::DAY_${i}"; |
602
|
28
|
|
|
|
|
115
|
my $const = I18N::Langinfo->can( "DAY_${i}" ); |
603
|
|
|
|
|
|
|
# $long->[$i-1] = langinfo( &$const ); |
604
|
28
|
|
|
|
|
114
|
$long->[$i-1] = langinfo( $const->() ); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
4
|
50
|
|
|
|
52
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
608
|
|
|
|
|
|
|
|
609
|
4
|
|
|
|
|
16
|
return( [ $short, $long ] ); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
sub _get_months |
613
|
|
|
|
|
|
|
{ |
614
|
2
|
|
|
2
|
|
415
|
my $self = shift( @_ ); |
615
|
2
|
|
|
|
|
7
|
my $locale = shift( @_ ); |
616
|
2
|
|
|
|
|
11
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
617
|
2
|
|
|
|
|
9
|
my $short = $self->new_array; |
618
|
2
|
|
|
|
|
33
|
my $long = $self->new_array; |
619
|
|
|
|
|
|
|
|
620
|
2
|
50
|
|
|
|
36
|
POSIX::setlocale( &POSIX::LC_ALL, $locale ) if( defined( $locale ) ); |
621
|
|
|
|
|
|
|
|
622
|
2
|
|
|
|
|
25
|
for( my $i = 1; $i <= 12; $i++ ) |
623
|
|
|
|
|
|
|
{ |
624
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::ABMON_${i}"; |
625
|
|
|
|
|
|
|
# $short->[$i-1] = langinfo( &$const ); |
626
|
24
|
|
|
|
|
173
|
my $const = I18N::Langinfo->can( "ABMON_${i}" ); |
627
|
24
|
|
|
|
|
116
|
$short->[$i-1] = langinfo( $const->() ); |
628
|
|
|
|
|
|
|
} |
629
|
2
|
|
|
|
|
9
|
for( my $i = 1; $i <= 12; $i++ ) |
630
|
|
|
|
|
|
|
{ |
631
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::MON_${i}"; |
632
|
|
|
|
|
|
|
# $long->[$i-1] = langinfo( &$const ); |
633
|
24
|
|
|
|
|
179
|
my $const = I18N::Langinfo->can( "MON_${i}" ); |
634
|
24
|
|
|
|
|
125
|
$long->[$i-1] = langinfo( $const->() ); |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
2
|
50
|
|
|
|
38
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
638
|
|
|
|
|
|
|
|
639
|
2
|
|
|
|
|
9
|
return( [ $short, $long ] ); |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub _get_numeric_dict |
643
|
|
|
|
|
|
|
{ |
644
|
2
|
|
|
2
|
|
379
|
my $self = shift( @_ ); |
645
|
2
|
|
|
|
|
8
|
my $locale = shift( @_ ); |
646
|
2
|
|
|
|
|
10
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
647
|
2
|
50
|
|
|
|
19
|
POSIX::setlocale( &POSIX::LC_ALL, $locale) if( defined( $locale ) ); |
648
|
2
|
|
|
|
|
29
|
my $lconv = POSIX::localeconv(); |
649
|
2
|
50
|
|
|
|
25
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
650
|
2
|
|
|
|
|
26
|
my $def = $self->new_hash; |
651
|
|
|
|
|
|
|
@$def{qw( currency decimal int_currency negative_sign thousand precision )} = |
652
|
2
|
|
|
|
|
992
|
@$lconv{qw( currency_symbol decimal_point int_curr_symbol negative_sign thousands_sep frac_digits )}; |
653
|
2
|
|
|
2
|
|
18
|
use utf8; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
16
|
|
654
|
2
|
50
|
33
|
|
|
196
|
$def->{currency} = '€' if( CORE::exists( $def->{currency} ) && defined( $def->{currency} ) && $def->{currency} eq 'EUR' ); |
|
|
|
33
|
|
|
|
|
655
|
2
|
0
|
33
|
|
|
99
|
$lconv->{currency_symbol} = '€' if( CORE::exists( $lconv->{currency_symbol} ) && defined( $lconv->{currency_symbol} ) && $lconv->{currency_symbol} eq 'EUR' ); |
|
|
|
33
|
|
|
|
|
656
|
2
|
50
|
33
|
|
|
9
|
$lconv->{grouping} = unpack( "C*", $lconv->{grouping} ) if( CORE::exists( $lconv->{grouping} ) && defined( $lconv->{grouping} ) ); |
657
|
2
|
50
|
33
|
|
|
9
|
$lconv->{mon_grouping} = unpack( "C*", $lconv->{mon_grouping} ) if( CORE::exists( $lconv->{mon_grouping} ) && defined( $lconv->{mon_grouping} ) ); |
658
|
2
|
|
|
|
|
6
|
$lconv = $self->new_hash( $lconv ); |
659
|
2
|
|
|
|
|
1022
|
return( [ $def, $lconv ] ); |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
sub _get_po |
663
|
|
|
|
|
|
|
{ |
664
|
15
|
|
|
15
|
|
48
|
my $self = shift( @_ ); |
665
|
15
|
|
|
|
|
64
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
666
|
15
|
|
|
|
|
213
|
return( $hash->{_po} ); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# NOTE: Text::PO::String class |
670
|
|
|
|
|
|
|
{ |
671
|
|
|
|
|
|
|
package |
672
|
|
|
|
|
|
|
Text::PO::String; |
673
|
|
|
|
|
|
|
BEGIN |
674
|
0
|
|
|
|
|
0
|
{ |
675
|
2
|
|
|
2
|
|
433
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
45
|
|
676
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
58
|
|
677
|
2
|
|
|
2
|
|
11
|
use parent qw( Module::Generic ); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
11
|
|
678
|
2
|
|
|
2
|
|
123
|
use vars qw( $VERSION ); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
147
|
|
679
|
2
|
|
|
2
|
|
173
|
our $VERSION = 'v0.1.0'; |
680
|
|
|
|
|
|
|
use overload ( |
681
|
|
|
|
|
|
|
'""' => 'as_string', |
682
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
683
|
2
|
|
|
|
|
23
|
fallback => 1, |
684
|
2
|
|
|
2
|
|
13
|
); |
|
2
|
|
|
|
|
4
|
|
685
|
|
|
|
|
|
|
}; |
686
|
|
|
|
|
|
|
|
687
|
2
|
|
|
2
|
|
27
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
39
|
|
688
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
356
|
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
sub init |
691
|
|
|
|
|
|
|
{ |
692
|
4
|
|
|
4
|
|
412
|
my $self = shift( @_ ); |
693
|
4
|
|
|
|
|
11
|
my $value = shift( @_ ); |
694
|
4
|
|
|
|
|
11
|
my $locale = shift( @_ ); |
695
|
4
|
|
|
|
|
79
|
$self->{locale} = $locale; |
696
|
4
|
|
|
|
|
18
|
$self->{value} = $value; |
697
|
4
|
|
|
|
|
32
|
$self->SUPER::init( @_ ); |
698
|
4
|
|
|
|
|
251
|
return( $self ); |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
4
|
|
|
4
|
|
1577
|
sub as_string { return( shift->value->scalar ); } |
702
|
|
|
|
|
|
|
|
703
|
0
|
|
|
0
|
|
0
|
sub locale { return( shift->_set_get_scalar_as_object( 'locale', @_ ) ); } |
704
|
|
|
|
|
|
|
|
705
|
4
|
|
|
4
|
|
40
|
sub value { return( shift->_set_get_scalar_as_object( 'value', @_ ) ); } |
706
|
|
|
|
|
|
|
|
707
|
0
|
|
|
0
|
|
|
sub TO_JSON { return( shift->as_string ); } |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
1; |
711
|
|
|
|
|
|
|
# NOTE: POD |
712
|
|
|
|
|
|
|
__END__ |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=encoding utf-8 |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=head1 NAME |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
Text::PO::Gettext - A GNU Gettext implementation |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=head1 SYNOPSIS |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
use Text::PO::Gettext; |
723
|
|
|
|
|
|
|
my $po = Text::PO::Gettext->new || die( Text::PO::Gettext->error, "\n" ); |
724
|
|
|
|
|
|
|
my $po = Text::PO::Gettext->new({ |
725
|
|
|
|
|
|
|
category => 'LC_MESSAGES', |
726
|
|
|
|
|
|
|
debug => 3, |
727
|
|
|
|
|
|
|
domain => "com.example.api", |
728
|
|
|
|
|
|
|
locale => 'ja-JP', |
729
|
|
|
|
|
|
|
path => "/home/joe/locale", |
730
|
|
|
|
|
|
|
use_json => 1, |
731
|
|
|
|
|
|
|
}) || die( Text::PO::Gettext->error, "\n" ); |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=head1 VERSION |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
v0.3.0 |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=head1 DESCRIPTION |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
This module is used to access the data in either C<po>, C<mo> or C<json> file and provides various methods to access those data. |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
The conventional way to use GNU gettext is to set the global environment variable C<LANGUAGE> (not C<LANG> by the way. GNU gettext only uses C<LANGUAGE>), then set the L<POSIX/setlocale> to the language such as: |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
use Locale::gettext; |
744
|
|
|
|
|
|
|
use POSIX (); |
745
|
|
|
|
|
|
|
POSIX::setlocale( &POSIX::LC_ALL, 'ja_JP' ); |
746
|
|
|
|
|
|
|
my $d = Locale::gettext->domain( 'com.example.api' ); |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
And then in your application, you would write a statement like: |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
print $d->get( 'Hello!' ); |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
Or possibly using direct access to the C function: |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
use Locale::gettext; |
755
|
|
|
|
|
|
|
use POSIX (); |
756
|
|
|
|
|
|
|
POSIX::setlocale( &POSIX::LC_ALL, 'ja_JP' ); |
757
|
|
|
|
|
|
|
textdomain( 'com.example.api' ); |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
And then: |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
print gettext( 'Hello!' ); |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
See L<Locale::gettext> for more on this. |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
This works fine, but has the inconvenience that it uses the global C<LANGUAGE> environment variable and makes it less than subpar as to the necessary flexibility when using multiple domains and flipping back and forth among locales. |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
Thus comes a more straightforward object-oriented interface offered by this module. |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
You instantiate an object, passing the domain, the locale and the filesystem path where the locale data resides. |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
my $po = Text::PO::Gettext->new( |
772
|
|
|
|
|
|
|
domain => 'com.example.api', |
773
|
|
|
|
|
|
|
locale => 'ja_JP', |
774
|
|
|
|
|
|
|
path => '/some/where/locale' |
775
|
|
|
|
|
|
|
); |
776
|
|
|
|
|
|
|
print $po->gettext( 'Hello!' ); |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
This will load into memory the locale data whether they are stored as C<.po>, C<.mo> or even C<.json> file, thus making calls to L</gettext> super fast since they are in memory. |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
More than one locale can be loaded, each with its own L<Text::PO::Gettext> object |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
This distribution comes with its Javascript library equivalent. See the C<share> folder alone with its own test units. |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
Also, there is a script in C<scripts> that can be used to transcode C<.po> or C<.mo> files into json format and vice versa. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
Still, it is better to convert the original C<.po> files to json using the C<po.pl> utility that comes in this L<Text::PO> distribution since it would allow the standalone JavaScript library to read json-based po files. For example: |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
./po.pl --as-json --output /home/joe/www/locale/ja_JP/LC_MESSAGES/com.example.api.json ./ja_JP.po |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
This api supports locale that use hyphens or underscore in them such as C<en-GB> or C<en_GB>. You can use either, it will be converted internally. |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=head2 new |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
Takes the following options and returns a Gettext object. |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=over 4 |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
=item * C<category> |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
If I<category> is defined, such as C<LC_MESSAGES> (by default), it will be used when building the I<path>. |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
Other possible category values are: C<LC_CTYPE>, C<LC_NUMERIC>, C<LC_TIME>, C<LC_COLLATE>, C<LC_MONETARY> |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
See L<GNU documentation for more information|https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html> and L<perllocale/"LOCALE CATEGORIES"> |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
On the web, using the path is questionable. |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
See the L<GNU documentation|https://www.gnu.org/software/libc/manual/html_node/Using-gettextized-soft |
811
|
|
|
|
|
|
|
ware.html> for more information on this. |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
=item * C<domain> |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
The portable object domain, such as C<com.example.api> |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=item * C<locale> |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
The locale, such as C<ja_JP>, or C<en>, or it could even contain a dash instead of an underscore, such as C<en-GB>. Internally, though, this will be converted to underscore. |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
=item * C<path> |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
The uri path where the gettext localised data are. |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
This is used to form a path along with the locale string. For example, with a locale of C<ja_JP> and a domain of C<com/example.api>, if the path were C</locale>, the data po json data would be fetched from C</locale/ |
826
|
|
|
|
|
|
|
ja_JP/LC_MESSAGES/com.example.api.json> |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=back |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
=head1 METHODS |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
=head2 addItem |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
This takes a C<locale>, a message id and its localised version and it will add this to the current dictionary for the current domain. |
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
$po->addItem( 'ja_JP', 'Hello!' => "今日は!" ); |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=head2 category |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
The category to use. This defaults to C<LC_MESSAGES>, but if you prefer you can nix its use by making it undefined, or empty: |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
my $po = Text::PO::Gettext->new( |
843
|
|
|
|
|
|
|
category => '', |
844
|
|
|
|
|
|
|
domain => 'com.example.api', |
845
|
|
|
|
|
|
|
locale => 'ja_JP', |
846
|
|
|
|
|
|
|
path => '/some/where/locale' |
847
|
|
|
|
|
|
|
); |
848
|
|
|
|
|
|
|
# Setting category to empty string will have the module get the po data |
849
|
|
|
|
|
|
|
# under C</some/where/locale/ja_JP/com.example.api.json> for example. |
850
|
|
|
|
|
|
|
print $po->gettext( 'Hello!' ); |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
=head2 charset |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
Returns a string containing the value of the charset encoding as defined in the C<Content-Type> header. |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
$po->charset() |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=head2 contentEncoding |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Content-Encoding>. |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
$po->contentEncoding(); |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
=head2 contentType |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Content-Type>. |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
$po->contentType(); # text/plain; charset=utf-8 |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=head2 currentLang |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
Return the current globally used locale. This is the value found in environment variables C<LANGUAGE> or C<LANG>. Note that GNU gettext only recognises C<LANGUAGE> |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
and thus, this is different from the C<locale> set in the Gettext class object using </setLocale> or upon class object instantiation. |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=head2 dgettext |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
Takes a domain and a message id and returns the equivalent localised string if any, otherwise the original message id. |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
$po->dgettext( 'com.example.auth', 'Please enter your e-mail address' ); |
881
|
|
|
|
|
|
|
# Assuming the locale currently set is ja_JP, this would return: |
882
|
|
|
|
|
|
|
# 電子メールアドレスをご入力下さい。 |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=head2 dngettext |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
Same as L</ngettext>, but takes also a domain as first argument. For example: |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
$po->ngettext( 'com.example.auth', '%d comment awaiting moderation', '%d comments awaiting moderation', 12 ); |
889
|
|
|
|
|
|
|
# Assuming the locale is ru_RU, this would return: |
890
|
|
|
|
|
|
|
# %d комментариев ожидают проверки |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
Note that as of version C<v0.5.0>, this returns a C<Text::PO::String>, which is lightweight and stringifies automatically. It provides the benefit of tagging the string with the locale attached to it. |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
Thus, in the example above, the resulting C<Text::PO::String> would have its method C<locale> value set to C<ru_RU>, and you could do: |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
my $localised = $po->ngettext( 'com.example.auth', '%d comment awaiting moderation', '%d comments awaiting moderation', 12 ); |
897
|
|
|
|
|
|
|
say "Locale for this string is: ", $localised->locale; |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
If no locale string was found, C<locale> would be undefined. |
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=head2 domain |
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
Sets or gets the domain. |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
$po->domain( 'com.example.api' ); |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
By doing so, this will call L</textdomain> and load the associated data from file, if any are found. |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
=head2 exists |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
Provided with a locale, and this returns true if the locale exists in the current domain, or false otherwise. |
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
=head2 fetchLocale |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
Given an original string (msgid), this returns an array of <span> html element each for one language and its related localised content. For example: |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
my $array = $po->fetchLocale( "Hello!" ); |
918
|
|
|
|
|
|
|
# Returns: |
919
|
|
|
|
|
|
|
<span lang="de-DE">Grüß Gott!</span> |
920
|
|
|
|
|
|
|
<span lang="fr-FR">Salut !</span> |
921
|
|
|
|
|
|
|
<span lang="ja-JP">今日は!</span> |
922
|
|
|
|
|
|
|
<span lang="ko-KR">안녕하세요!</span> |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
This is designed to be added to the html, and based on C<lang> attribute of the C<html> tag, and using the following css trick, this will automatically display the right localised data: |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
[lang=de-DE] [lang=en-GB], |
927
|
|
|
|
|
|
|
[lang=de-DE] [lang=fr-FR], |
928
|
|
|
|
|
|
|
[lang=de-DE] [lang=ja-JP], |
929
|
|
|
|
|
|
|
[lang=de-DE] [lang=ko-KR], |
930
|
|
|
|
|
|
|
[lang=en-GB] [lang=de-DE], |
931
|
|
|
|
|
|
|
[lang=en-GB] [lang=fr-FR], |
932
|
|
|
|
|
|
|
[lang=en-GB] [lang=ja-JP], |
933
|
|
|
|
|
|
|
[lang=en-GB] [lang=ko-KR], |
934
|
|
|
|
|
|
|
[lang=fr-FR] [lang=de-DE], |
935
|
|
|
|
|
|
|
[lang=fr-FR] [lang=en-GB], |
936
|
|
|
|
|
|
|
[lang=fr-FR] [lang=ja-JP], |
937
|
|
|
|
|
|
|
[lang=fr-FR] [lang=ko-KR], |
938
|
|
|
|
|
|
|
[lang=ja-JP] [lang=de-DE], |
939
|
|
|
|
|
|
|
[lang=ja-JP] [lang=en-GB] |
940
|
|
|
|
|
|
|
[lang=ja-JP] [lang=fr-FR], |
941
|
|
|
|
|
|
|
[lang=ja-JP] [lang=ko-KR] |
942
|
|
|
|
|
|
|
{ |
943
|
|
|
|
|
|
|
display: none !important; |
944
|
|
|
|
|
|
|
visibility: hidden !important; |
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=head2 getDataPath |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
This takes no argument and will check for the environment variables C<TEXTDOMAINDIR>. If found, it will use this in lieu of the I<path> option used during object instantiation. |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
It returns the value found. This is just a helper method and does not affect the value of the I<path> property set during object instantiation. |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=head2 getDaysLong |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
Returns an array reference containing the 7 days of the week in their long representation. |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
my $ref = $po->getDaysLong(); |
958
|
|
|
|
|
|
|
# Assuming the locale is fr_FR, this would yield |
959
|
|
|
|
|
|
|
print $ref->[0], "\n"; # dim. |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
=head2 getDaysShort |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
Returns an array reference containing the 7 days of the week in their short representation. |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
my $ref = $po->getDaysShort(); |
966
|
|
|
|
|
|
|
# Assuming the locale is fr_FR, this would yield |
967
|
|
|
|
|
|
|
print $ref->[0], "\n"; # dimanche |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=head2 getDomainHash |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
This takes an optional hash of parameters and return the global hash dictionary used by this class to store the localised data. |
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# Will use the default domain as set in po.domain |
974
|
|
|
|
|
|
|
my $data = $po->getDomainHash(); |
975
|
|
|
|
|
|
|
# Explicitly specify another domain |
976
|
|
|
|
|
|
|
my $data = $po->getDomainHash( domain => "net.example.api" ); |
977
|
|
|
|
|
|
|
# Specify a domain and a locale |
978
|
|
|
|
|
|
|
my $l10n = $po->getDomainHash( domain => "com.example.api", locale => "ja_JP" ); |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
Possible options are: |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
=over 4 |
983
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
=item * C<domain> The domain for the data, such as C<com.example.api> |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=item * C<locale> The locale to return the associated dictionary. |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
=back |
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
=head2 getLangDataPath |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
Contrary to its JavaScript equivalent, this takes no parameter. It returns the value of the environment variable C<TEXTLOCALEDIR> if found. |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
This is used internally during object instantiation when the I<path> parameter is not provided. |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=head2 getLanguageDict |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
Provided with a locale, such as C<ja_JP> and this will return the dictionary for the current domain and the given locale. |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
=head2 getLocale |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
Returns the locale set for the current object, such as C<fr_FR> or C<ja_JP> |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
Locale returned are always formatted for the server-side, which means having an underscore rather than an hyphen like in the web environment. |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
=head2 getLocales |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
Provided with a C<msgid> (i.e. an original text) and this will call L</fetchLocale> and return those C<span> tags as a string containing their respective localised content, joined by a new line |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
=head2 getLocalesf |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
This is similar to L</getLocale>, except that it does a sprintf internally before returning the resulting value. |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
=head2 getMetaKeys |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
Returns an array of the meta field names used. |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
=head2 getMetaValue |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
Provided with a meta field name and this returns its corresponding value. |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=head2 getMonthsLong |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
Returns an array reference containing the 12 months in their long representation. |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
my $ref = $po->getMonthsLong(); |
1027
|
|
|
|
|
|
|
# Assuming the locale is fr_FR, this would yield |
1028
|
|
|
|
|
|
|
print $ref->[0], "\n"; # janvier |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
=head2 getMonthsShort |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
Returns an array reference containing the 12 months in their short representation. |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
my $ref = $po->getMonthsShort(); |
1035
|
|
|
|
|
|
|
# Assuming the locale is fr_FR, this would yield |
1036
|
|
|
|
|
|
|
print $ref->[0], "\n"; # janv. |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
=head2 getNumericDict |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
Returns an hash reference containing the following properties: |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
my $ref = $po->getNumericDict(); |
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
=over 4 |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
=item * C<currency> string |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
Contains the usual currency symbol, such as C<€>, or C<$>, or C<¥> |
1049
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
=item * C<decimal> string |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
Contains the character used to separate decimal. In English speaking countries, this would typically be a dot. |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
=item * C<int_currency> string |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
Contains the 3-letters international currency symbol, such as C<USD>, or C<EUR> or C<JPY> |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
=item * C<negative_sign> string |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
Contains the negative sign used for negative number |
1061
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
=item * C<precision> integer |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
An integer whose value represents the fractional precision allowed for monetary context. |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
For example, in Japanese, this value would be 0 while in many other countries, it would be 2. |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
=item * C<thousand> string |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Contains the character used to group and separate thousands. |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
For example, in France, it would be a space, such as : |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
1 000 000,00 |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
While in English countries, including Japan, it would be a comma : |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
1,000,000.00 |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=back |
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=head2 getNumericPosixDict |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
Returns the full hash reference returned by L<POSIX/lconv>. It contains the following properties: |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
Here the values shown as example are for the locale C<en_US> |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
=over 4 |
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
=item * C<currency_symbol> string |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
The local currency symbol: C<$> |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
=item * C<decimal_point> string |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
The decimal point character, except for currency values, cannot be an empty string: C<.> |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=item * C<frac_digits> integer |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
The number of digits after the decimal point in the local style for currency value: 2 |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=item * C<grouping> |
1103
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
The sizes of the groups of digits, except for currency values. unpack( "C*", $grouping ) will give the number |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=item * C<int_curr_symbol> string |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
The standardized international currency symbol: C<USD> |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=item * C<int_frac_digits> integer |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
The number of digits after the decimal point in an international-style currency value: 2 |
1113
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
=item * C<int_n_cs_precedes> integer |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
Same as n_cs_precedes, but for internationally formatted monetary quantities: 1 |
1117
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
=item * C<int_n_sep_by_space> integer |
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
Same as n_sep_by_space, but for internationally formatted monetary quantities: 1 |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
=item * C<int_n_sign_posn> integer |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
Same as n_sign_posn, but for internationally formatted monetary quantities: 1 |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
=item * C<int_p_cs_precedes> integer |
1127
|
|
|
|
|
|
|
|
1128
|
|
|
|
|
|
|
Same as p_cs_precedes, but for internationally formatted monetary quantities: 1 |
1129
|
|
|
|
|
|
|
|
1130
|
|
|
|
|
|
|
=item * C<int_p_sep_by_space> integer |
1131
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
Same as p_sep_by_space, but for internationally formatted monetary quantities: 1 |
1133
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
=item * C<int_p_sign_posn> integer |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
Same as p_sign_posn, but for internationally formatted monetary quantities: 1 |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
=item * C<mon_decimal_point> string |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
The decimal point character for currency values: C<.> |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
=item * C<mon_grouping> |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
Like grouping but for currency values. |
1145
|
|
|
|
|
|
|
|
1146
|
|
|
|
|
|
|
=item * C<mon_thousands_sep> string |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
The separator for digit groups in currency values: C<,> |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
=item * C<n_cs_precedes> integer |
1151
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
Like p_cs_precedes but for negative values: 1 |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
=item * C<n_sep_by_space> integer |
1155
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
Like p_sep_by_space but for negative values: 0 |
1157
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
=item * C<n_sign_posn> integer |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
Like p_sign_posn but for negative currency values: 1 |
1161
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
=item * C<negative_sign> string |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
The character used to denote negative currency values, usually a minus sign: C<-> |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
=item * C<p_cs_precedes> integer |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
1 if the currency symbol precedes the currency value for nonnegative values, 0 if it follows: 1 |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=item * C<p_sep_by_space> integer |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
1 if a space is inserted between the currency symbol and the currency value for nonnegative values, 0 otherwise: 0 |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
=item * C<p_sign_posn> integer |
1175
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
The location of the positive_sign with respect to a nonnegative quantity and the currency_symbol, coded as follows: |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
0 Parentheses around the entire string. |
1179
|
|
|
|
|
|
|
1 Before the string. |
1180
|
|
|
|
|
|
|
2 After the string. |
1181
|
|
|
|
|
|
|
3 Just before currency_symbol. |
1182
|
|
|
|
|
|
|
4 Just after currency_symbol. |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
=item * C<positive_sign> string |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
The character used to denote nonnegative currency values, usually the empty string |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
=item * C<thousands_sep> string |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
The separator between groups of digits before the decimal point, except for currency values: C<,> |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
=back |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
=head2 getPlural |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
Calls L<Text::PO/plural> and returns an array object (L<Module::Generic::Array>) with 2 elements. |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
See L<Text::PO/plural> for more details. |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
=head2 getText |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
Provided with an original string, and this will return its localised equivalent if it exists, or by default, it will return the original string. |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
=head2 getTextf |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
Provided with an original string, and this will get its localised equivalent that wil be used as a template for the sprintf function. The resulting formatted localised content will be returned. |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
=head2 gettext |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
Provided with a C<msgid> represented by a string, and this return a localised version of the string, if any is found and is translated, otherwise returns the C<msgid> that was provided. |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
$po->gettext( "Hello" ); |
1213
|
|
|
|
|
|
|
# With locale of fr_FR, this would return "Bonjour" |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
See the global function L</_> for more information. |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
Note that as of version C<v0.5.0>, this returns a C<Text::PO::String>, which is lightweight and stringifies automatically. It provides the benefit of tagging the string with the locale attached to it. |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
Thus, in the example above, the resulting C<Text::PO::String> would have its method C<locale> value set to C<fr_FR>, and you could do: |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
my $localised = $po->gettext( "Hello" ); |
1222
|
|
|
|
|
|
|
say "Locale for this string is: ", $localised->locale; |
1223
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
If no locale string was found, C<locale> would be undefined. |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
=head2 gettextf |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
This is an alias to L</getTextf> |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
=head2 isSupportedLanguage |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
Provided with a locale such as C<fr-FR> or C<ja_JP> no matter whether an underscore or a dash is used, and this will return true if the locale has already been loaded and thus is supported. False otherwise. |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
=head2 language |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Language>. |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
$po->language(); |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
=head2 languageTeam |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Language-Team>. |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
$po->languageTeam(); |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
=head2 lastTranslator |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Last-Translator>. |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
$po->lastTranslator(); |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
=head2 locale |
1253
|
|
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
Returns the locale set in the object. if sets, this will trigger the (re)load of po data by calling L</textdomain> |
1255
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
=head2 locale_unix |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
Provided with a locale, such as C<en-GB> and this will return its equivalent formatted for server-side such as C<en_GB> |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
=head2 locale_web |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
Provided with a locale, such as C<en_GB> and this will return its equivalent formatted for the web such as C<en-GB> |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
=head2 mimeVersion |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
Returns a string containing the value of the header C<MIME-Version>. |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
$po->mimeVersion(); |
1269
|
|
|
|
|
|
|
|
1270
|
|
|
|
|
|
|
=head2 ngettext |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
Takes an original string (a.k.a message id), the plural version of that string, and an integer representing the applicable count. For example: |
1273
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
$po->ngettext( '%d comment awaiting moderation', '%d comments awaiting moderation', 12 ); |
1275
|
|
|
|
|
|
|
# Assuming the locale is ru_RU, this would return: |
1276
|
|
|
|
|
|
|
# %d комментариев ожидают проверки |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
=head2 path |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
Sets or gets the filesystem path to the base directory containing the locale data: |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
$po->path( '/locale' ); # /locale contains en_GB/LC_MESSAGES/com.example.api.mo for example |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
=head2 plural |
1285
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
Sets or gets the definition for plural for the current domain and locale. |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
It takes and returns an array reference of 2 elements: |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
=over 4 |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
=item 0. An integer representing the various plural forms available, starting from 1 |
1293
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
=item 1. An expression to be evaluated resulting in an offset for the right plural form. For example: |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
n>1 |
1297
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
or more complex for Russian: |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
(n==1) ? 0 : (n%10==1 && n%100!=11) ? 3 : ((n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20)) ? 1 : 2) |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
=back |
1303
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
=head2 pluralForms |
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Plural-Forms>. |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
$po->pluralForms(); |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
=head2 po_object |
1311
|
|
|
|
|
|
|
|
1312
|
|
|
|
|
|
|
Returns the L<Text::PO> object used. |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
=head2 poRevisionDate |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
Returns a string containing the value of the header C<PO-Revision-Date>. |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
$po->poRevisionDate(); |
1319
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
=head2 potCreationDate |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
Returns a string containing the value of the header C<POT-Creation-Date>. |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
$po->potCreationDate(); |
1325
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
=head2 projectIdVersion |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Project-Id-Version>. |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
$po->projectIdVersion(); |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
=head2 reportBugsTo |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
Returns a string containing the value of the header C<Report-Msgid-Bugs-To>. |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
$po->reportBugsTo(); |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
=head2 textdomain |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
Given a string representing a domain, such as C<com.example.api> and this will load the C<.json> (if the L</use_json> option is enabled), C<.po> or C<.mo> file found in that order. |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
=head2 use_json |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
Takes a boolean and if set, L<Text::PO::Gettext> will use a json po data if it exists, otherwise it will use a C<.po> file or a C<.mo> file in that order of preference. |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
=head2 _get_po |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
Returns the L<Text::PO> object used. |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
=head1 AUTHOR |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
=head1 SEE ALSO |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
L<perl> |
1357
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
Copyright(c) 2021 DEGUEST Pte. Ltd. DEGUEST Pte. Ltd. |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
=cut |