| 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
|
|
301044
|
use strict; |
|
|
2
|
|
|
|
|
11
|
|
|
|
2
|
|
|
|
|
60
|
|
|
17
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
51
|
|
|
18
|
2
|
|
|
2
|
|
11
|
use warnings::register; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
224
|
|
|
19
|
2
|
|
|
2
|
|
11
|
use parent qw( Module::Generic ); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
9
|
|
|
20
|
2
|
|
|
2
|
|
136
|
use vars qw( $VERSION $L10N $DOMAIN_RE $LOCALE_RE ); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
127
|
|
|
21
|
2
|
|
|
2
|
|
422
|
use I18N::Langinfo qw( langinfo ); |
|
|
2
|
|
|
|
|
708
|
|
|
|
2
|
|
|
|
|
116
|
|
|
22
|
2
|
|
|
2
|
|
12
|
use POSIX (); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
44
|
|
|
23
|
2
|
|
|
2
|
|
598
|
use Text::PO; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
18
|
|
|
24
|
|
|
|
|
|
|
# l10n_id => lang => string => local string |
|
25
|
2
|
|
|
2
|
|
889
|
our $L10N = {}; |
|
26
|
2
|
|
|
|
|
10
|
our $DOMAIN_RE = qr/^[a-z]+(\.[a-zA-Z0-9\_\-]+)*$/; |
|
27
|
2
|
|
|
|
|
6
|
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
|
|
|
|
|
44
|
our $VERSION = 'v0.3.0'; |
|
39
|
|
|
|
|
|
|
}; |
|
40
|
|
|
|
|
|
|
|
|
41
|
2
|
|
|
2
|
|
13
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
50
|
|
|
42
|
2
|
|
|
2
|
|
11
|
use warnings; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
1264
|
|
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub init |
|
45
|
|
|
|
|
|
|
{ |
|
46
|
2
|
|
|
2
|
1
|
492792
|
my $self = shift( @_ ); |
|
47
|
2
|
|
|
|
|
111
|
$self->{category} = 'LC_MESSAGES'; |
|
48
|
2
|
|
|
|
|
31
|
$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
|
|
|
63
|
$self->{locale} = $ENV{LANG} || $ENV{LANGUAGE}; |
|
52
|
2
|
|
|
|
|
29
|
$self->{path} = ''; |
|
53
|
2
|
|
|
|
|
32
|
$self->{plural} = []; |
|
54
|
2
|
|
|
|
|
24
|
$self->{use_json} = 1; |
|
55
|
2
|
|
|
|
|
11
|
$self->{_init_strict_use_sub} = 1; |
|
56
|
2
|
|
|
|
|
55
|
$self->{_init_params_order} = [qw( category path domain locale plural use_json )]; |
|
57
|
2
|
50
|
|
|
|
44
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
|
58
|
2
|
50
|
33
|
|
|
1724
|
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
|
|
|
|
|
19797
|
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
|
4813
|
sub category { return( shift->_set_get_scalar_as_object( 'category', @_ ) ); } |
|
83
|
|
|
|
|
|
|
|
|
84
|
1
|
|
|
1
|
1
|
1645
|
sub charset { return( shift->_get_po->charset ); } |
|
85
|
|
|
|
|
|
|
|
|
86
|
1
|
|
|
1
|
1
|
1094
|
sub contentEncoding { return( shift->_get_po->content_encoding ); } |
|
87
|
|
|
|
|
|
|
|
|
88
|
1
|
|
|
1
|
1
|
6
|
sub contentType { return( shift->_get_po->content_type ); } |
|
89
|
|
|
|
|
|
|
|
|
90
|
1
|
|
|
1
|
1
|
7
|
sub currentLang { return( shift->_get_po->current_lang ); } |
|
91
|
|
|
|
|
|
|
|
|
92
|
1
|
|
|
1
|
1
|
710
|
sub dgettext { return( shift->dngettext( @_ ) ); } |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub dngettext |
|
95
|
|
|
|
|
|
|
{ |
|
96
|
14
|
|
|
14
|
1
|
6261
|
my $self = shift( @_ ); |
|
97
|
14
|
|
|
|
|
31
|
my $opts = {}; |
|
98
|
14
|
100
|
|
|
|
67
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
|
99
|
14
|
|
|
|
|
72
|
my( $domain, $msgid, $msgidPlural, $count ) = @_; |
|
100
|
14
|
|
|
|
|
38
|
my $default; |
|
101
|
|
|
|
|
|
|
my $index; |
|
102
|
14
|
100
|
66
|
|
|
113
|
if( !defined( $count ) || $count !~ /^\d+$/ ) |
|
103
|
|
|
|
|
|
|
{ |
|
104
|
10
|
|
33
|
|
|
67
|
$default = $msgidPlural || $msgid; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
14
|
100
|
100
|
|
|
108
|
if( !exists( $opts->{locale} ) || !length( $opts->{locale} ) ) |
|
107
|
|
|
|
|
|
|
{ |
|
108
|
7
|
|
|
|
|
34
|
$opts->{locale} = $self->locale; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
14
|
|
|
|
|
5837
|
my $hash = $self->getDomainHash({ domain => $domain }); |
|
111
|
14
|
|
|
|
|
81
|
my $plural = $self->plural; |
|
112
|
14
|
50
|
|
|
|
11438
|
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
|
|
|
|
|
90
|
my $l10n = $hash->{ $opts->{locale} }; |
|
118
|
14
|
|
|
|
|
85
|
my $dict = $l10n->{ $msgid }; |
|
119
|
14
|
50
|
|
|
|
42
|
if( $dict ) |
|
120
|
|
|
|
|
|
|
{ |
|
121
|
14
|
50
|
|
|
|
85
|
if( $plural->length == 0 ) |
|
122
|
|
|
|
|
|
|
{ |
|
123
|
0
|
|
|
|
|
0
|
$plural = $self->getPlural(); |
|
124
|
|
|
|
|
|
|
} |
|
125
|
14
|
100
|
|
|
|
509751
|
if( ref( $dict->{msgstr} ) eq 'ARRAY' ) |
|
126
|
|
|
|
|
|
|
{ |
|
127
|
4
|
50
|
33
|
|
|
558
|
if( $self->_is_number( $count ) && |
|
128
|
|
|
|
|
|
|
int( $plural->[0] ) > 0 ) |
|
129
|
|
|
|
|
|
|
{ |
|
130
|
2
|
|
|
2
|
|
15
|
no warnings 'once'; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
6453
|
|
|
131
|
4
|
|
|
|
|
1132
|
my $n = $count; |
|
132
|
4
|
|
|
|
|
11
|
my $expr = $plural->[1]; |
|
133
|
4
|
|
|
|
|
37
|
$expr =~ s/(?:^|\b)(?<!\$)(n)(?:\b|$)/\$$1/g; |
|
134
|
4
|
|
|
|
|
226
|
$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
|
|
|
|
|
38
|
my $locale_str = join( '', @{$dict->{msgstr}->[ $index ]} ); |
|
|
4
|
|
|
|
|
23
|
|
|
143
|
4
|
50
|
|
|
|
62
|
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
|
|
|
1477
|
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
|
2866
|
my $self = shift( @_ ); |
|
158
|
40
|
100
|
|
|
|
151
|
if( @_ ) |
|
159
|
|
|
|
|
|
|
{ |
|
160
|
2
|
|
|
|
|
15
|
my $v = shift( @_ ); |
|
161
|
2
|
50
|
|
|
|
132
|
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
|
|
|
|
|
43
|
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
|
|
|
|
|
20
|
$self->{domain} = $v; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
40
|
|
|
|
|
158
|
return( $self->_set_get_scalar_as_object( 'domain' ) ); |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub exists |
|
179
|
|
|
|
|
|
|
{ |
|
180
|
2
|
|
|
2
|
1
|
2468
|
my $self = shift( @_ ); |
|
181
|
2
|
|
|
|
|
12
|
my $lang = shift( @_ ); |
|
182
|
2
|
50
|
|
|
|
171
|
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
|
|
|
|
|
17
|
$lang = $self->locale_unix( $lang ); |
|
195
|
2
|
|
|
|
|
22
|
my $hash = $self->getDomainHash(); |
|
196
|
2
|
|
|
|
|
43
|
return( exists( $hash->{ $lang } ) ); |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub fetchLocale |
|
200
|
|
|
|
|
|
|
{ |
|
201
|
3
|
|
|
3
|
1
|
17
|
my $self = shift( @_ ); |
|
202
|
3
|
|
|
|
|
11
|
my $key = shift( @_ ); |
|
203
|
3
|
|
|
|
|
14
|
my $hash = $self->getDomainHash(); |
|
204
|
3
|
|
|
|
|
16
|
my $spans = []; |
|
205
|
|
|
|
|
|
|
# Browsing through each available locale language |
|
206
|
|
|
|
|
|
|
# Make it predictable using sort() |
|
207
|
3
|
|
|
|
|
43
|
foreach my $k ( sort( keys( %$hash ) ) ) |
|
208
|
|
|
|
|
|
|
{ |
|
209
|
6
|
|
|
|
|
40
|
my $locWeb = $self->locale_web( $k ); |
|
210
|
6
|
|
|
|
|
34
|
push( @$spans, "<span lang=\"${locWeb}\">" . $self->dngettext( $self->domain, $key, { locale => $k }) . '</span>' ); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
3
|
|
|
|
|
24
|
return( $self->new_array( $spans ) ); |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
2
|
|
|
2
|
1
|
171050
|
sub getDataPath { return( $ENV{TEXTDOMAINDIR} ); } |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub getDaysLong |
|
218
|
|
|
|
|
|
|
{ |
|
219
|
2
|
|
|
2
|
1
|
75507
|
my $self = shift( @_ ); |
|
220
|
2
|
|
|
|
|
10
|
my $opts = $self->_get_args_as_hash( @_ ); |
|
221
|
2
|
|
|
|
|
145
|
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
|
|
|
|
|
4
|
push( @$days, shift( @$days ) ); |
|
227
|
|
|
|
|
|
|
} |
|
228
|
2
|
|
|
|
|
9
|
return( $days ); |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub getDaysShort |
|
232
|
|
|
|
|
|
|
{ |
|
233
|
2
|
|
|
2
|
1
|
76108
|
my $self = shift( @_ ); |
|
234
|
2
|
|
|
|
|
11
|
my $opts = $self->_get_args_as_hash( @_ ); |
|
235
|
2
|
|
|
|
|
148
|
my $ref = $self->_get_days( $self->locale ); |
|
236
|
2
|
|
|
|
|
6
|
my $days = $ref->[0]; |
|
237
|
2
|
100
|
|
|
|
8
|
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
|
8992
|
my $self = shift( @_ ); |
|
248
|
38
|
|
|
|
|
149
|
my $opts = $self->_get_args_as_hash( @_ ); |
|
249
|
38
|
|
66
|
|
|
4271
|
$opts->{domain} //= $self->domain; |
|
250
|
|
|
|
|
|
|
|
|
251
|
38
|
|
|
|
|
19318
|
my $hash = $L10N; |
|
252
|
38
|
50
|
|
|
|
131
|
if( !exists( $hash->{ $opts->{domain} } ) ) |
|
253
|
|
|
|
|
|
|
{ |
|
254
|
0
|
|
|
|
|
0
|
retrn( $self->error( "No locale data for domain \"$opts->{domain}\"." ) ); |
|
255
|
|
|
|
|
|
|
} |
|
256
|
38
|
|
|
|
|
414
|
my $l10n = $hash->{ $opts->{domain} }; |
|
257
|
38
|
100
|
66
|
|
|
312
|
if( exists( $opts->{locale} ) && |
|
258
|
|
|
|
|
|
|
defined( $opts->{locale} ) ) |
|
259
|
|
|
|
|
|
|
{ |
|
260
|
18
|
|
|
|
|
85
|
$opts->{locale} = $self->locale_unix( $opts->{locale} ); |
|
261
|
18
|
50
|
|
|
|
100
|
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
|
|
|
|
|
80
|
return( $l10n ); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
2
|
|
|
2
|
1
|
132823
|
sub getLangDataPath { return( $ENV{TEXTLOCALEDIR} ); } |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub getLanguageDict |
|
273
|
|
|
|
|
|
|
{ |
|
274
|
2
|
|
|
2
|
1
|
2375
|
my $self = shift( @_ ); |
|
275
|
2
|
|
50
|
|
|
29
|
my $lang = shift( @_ ) || return( $self->error( "Language provided, to get its dictionary, is undefined or null." ) ); |
|
276
|
2
|
50
|
|
|
|
196
|
if( $lang !~ /^$LOCALE_RE$/ ) |
|
277
|
|
|
|
|
|
|
{ |
|
278
|
0
|
|
|
|
|
0
|
return( $self->error( "Locale provided (${lang}) is in an unsupported format." ) ); |
|
279
|
|
|
|
|
|
|
} |
|
280
|
2
|
|
|
|
|
28
|
$lang = $self->locale_unix( $lang ); |
|
281
|
|
|
|
|
|
|
|
|
282
|
2
|
100
|
|
|
|
44
|
if( !$self->isSupportedLanguage( $lang ) ) |
|
283
|
|
|
|
|
|
|
{ |
|
284
|
1
|
|
|
|
|
56
|
return( $self->error( "Language provided (${lang}), to get its dictionary, is unsupported." ) ); |
|
285
|
|
|
|
|
|
|
} |
|
286
|
1
|
|
|
|
|
24
|
my $hash = $self->getDomainHash(); |
|
287
|
1
|
50
|
|
|
|
11
|
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
|
12285
|
sub getLocale { return( shift->locale ); } |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub getLocales |
|
297
|
|
|
|
|
|
|
{ |
|
298
|
1
|
|
|
1
|
1
|
1494
|
my $self = shift( @_ ); |
|
299
|
1
|
|
50
|
|
|
20
|
my $key = shift( @_ ) || return( $self->error( "No text provided to get its localised equivalent" ) ); |
|
300
|
1
|
|
50
|
|
|
12
|
my $res = $self->fetchLocale( $key ) || return( $self->pass_error ); |
|
301
|
1
|
50
|
|
|
|
48
|
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
|
810
|
my $self = shift( @_ ); |
|
314
|
1
|
|
50
|
|
|
19
|
my $key = shift( @_ ) || return( $self->error( "No text provided to get its localised equivalent" ) ); |
|
315
|
1
|
|
50
|
|
|
5
|
my $res = $self->fetchLocale( $key ) || return( $self->pass_error ); |
|
316
|
1
|
50
|
|
|
|
56
|
if( scalar( @$res ) > 0 ) |
|
317
|
|
|
|
|
|
|
{ |
|
318
|
1
|
|
|
|
|
33
|
for( my $i = 0; $i < scalar( @$res ); $i++ ) |
|
319
|
|
|
|
|
|
|
{ |
|
320
|
2
|
|
|
|
|
22
|
$res->[$i] = sprintf( $res->[$i], @_ ); |
|
321
|
|
|
|
|
|
|
} |
|
322
|
1
|
|
|
|
|
12
|
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
|
876
|
my $self = shift( @_ ); |
|
333
|
1
|
|
|
|
|
16
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
|
334
|
1
|
|
50
|
|
|
60
|
my $po = $hash->{_po} || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
|
335
|
1
|
|
|
|
|
26
|
return( $po->meta_keys ); |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub getMetaValue |
|
339
|
|
|
|
|
|
|
{ |
|
340
|
1
|
|
|
1
|
1
|
37612
|
my $self = shift( @_ ); |
|
341
|
1
|
|
50
|
|
|
23
|
my $field = shift( @_ ) || return( $self->error( "No meta field provided to get its value." ) ); |
|
342
|
1
|
|
|
|
|
6
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
|
343
|
1
|
|
50
|
|
|
19
|
my $po = $hash->{_po} || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
|
344
|
1
|
|
|
|
|
21
|
return( $po->meta( $field ) ); |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub getMonthsLong |
|
348
|
|
|
|
|
|
|
{ |
|
349
|
1
|
|
|
1
|
1
|
492
|
my $self = shift( @_ ); |
|
350
|
1
|
|
|
|
|
4
|
my $ref = $self->_get_months( $self->locale ); |
|
351
|
1
|
|
|
|
|
5
|
return( $ref->[1] ); |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub getMonthsShort |
|
355
|
|
|
|
|
|
|
{ |
|
356
|
1
|
|
|
1
|
1
|
38884
|
my $self = shift( @_ ); |
|
357
|
1
|
|
|
|
|
5
|
my $ref = $self->_get_months( $self->locale ); |
|
358
|
1
|
|
|
|
|
11
|
return( $ref->[0] ); |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub getNumericDict |
|
362
|
|
|
|
|
|
|
{ |
|
363
|
1
|
|
|
1
|
1
|
37695
|
my $self = shift( @_ ); |
|
364
|
1
|
|
|
|
|
5
|
my $ref = $self->_get_numeric_dict( $self->locale ); |
|
365
|
1
|
|
|
|
|
12
|
return( $ref->[0] ); |
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub getNumericPosixDict |
|
369
|
|
|
|
|
|
|
{ |
|
370
|
1
|
|
|
1
|
1
|
4176
|
my $self = shift( @_ ); |
|
371
|
1
|
|
|
|
|
5
|
my $ref = $self->_get_numeric_dict( $self->locale ); |
|
372
|
1
|
|
|
|
|
12
|
return( $ref->[1] ); |
|
373
|
|
|
|
|
|
|
} |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub getPlural |
|
376
|
|
|
|
|
|
|
{ |
|
377
|
1
|
|
|
1
|
1
|
2
|
my $self = shift( @_ ); |
|
378
|
1
|
|
50
|
|
|
6
|
my $po = $self->_get_po || return( $self->error( "Unable to get the po object in the locale data hash" ) ); |
|
379
|
1
|
|
|
|
|
26
|
return( $po->plural ); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub getText |
|
383
|
|
|
|
|
|
|
{ |
|
384
|
2
|
|
|
2
|
1
|
725
|
my $self = shift( @_ ); |
|
385
|
2
|
|
|
|
|
6
|
my( $key, $lang ) = @_; |
|
386
|
2
|
50
|
33
|
|
|
23
|
return( $self->error( "No text to get its localised equivalent was provided." ) ) if( !defined( $key ) || !length( $key ) ); |
|
387
|
2
|
|
|
|
|
17
|
return( $self->dngettext( $self->domain, $key, { locale => $lang }) ); |
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub getTextf |
|
391
|
|
|
|
|
|
|
{ |
|
392
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
|
393
|
1
|
|
|
|
|
4
|
my $opts = {}; |
|
394
|
1
|
50
|
|
|
|
5
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
|
395
|
1
|
|
33
|
|
|
5
|
$opts->{lang} = $self->locale || $self->currentLang(); |
|
396
|
1
|
|
|
|
|
853
|
my $key = shift( @_ ); |
|
397
|
1
|
|
|
|
|
16
|
my $text = $self->getText( $key, $opts->{lang} ); |
|
398
|
1
|
|
|
|
|
13
|
return( sprintf( $text, @_ ) ); |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub gettext |
|
402
|
|
|
|
|
|
|
{ |
|
403
|
1
|
|
|
1
|
1
|
6
|
my $self = shift( @_ ); |
|
404
|
1
|
|
|
|
|
13
|
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
|
15
|
my $self = shift( @_ ); |
|
412
|
3
|
|
50
|
|
|
27
|
my $lang = shift( @_ ) || return(0); |
|
413
|
3
|
|
|
|
|
21
|
$lang = $self->locale_unix( $lang ); |
|
414
|
3
|
|
|
|
|
32
|
my $dom = $self->domain; |
|
415
|
3
|
50
|
|
|
|
2601
|
return( $self->error( "No domain \"$dom\" set!" ) ) if( !CORE::exists( $L10N->{ $dom } ) ); |
|
416
|
3
|
|
|
|
|
44
|
my $dict = $L10N->{ $dom }; |
|
417
|
3
|
100
|
|
|
|
43
|
if( CORE::exists( $dict->{ $lang } ) ) |
|
418
|
|
|
|
|
|
|
{ |
|
419
|
2
|
|
|
|
|
35
|
return(1); |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
else |
|
422
|
|
|
|
|
|
|
{ |
|
423
|
1
|
|
|
|
|
6
|
return(0); |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
|
|
427
|
1
|
|
|
1
|
1
|
16
|
sub language { return( shift->_get_po->language ); } |
|
428
|
|
|
|
|
|
|
|
|
429
|
1
|
|
|
1
|
1
|
723
|
sub languageTeam { return( shift->_get_po->language_team ); } |
|
430
|
|
|
|
|
|
|
|
|
431
|
1
|
|
|
1
|
1
|
732
|
sub lastTranslator { return( shift->_get_po->last_translator ); } |
|
432
|
|
|
|
|
|
|
|
|
433
|
1
|
|
|
1
|
1
|
756
|
sub mimeVersion { return( shift->_get_po->mime_version ); } |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub locale |
|
436
|
|
|
|
|
|
|
{ |
|
437
|
41
|
|
|
41
|
1
|
41990
|
my $self = shift( @_ ); |
|
438
|
41
|
100
|
|
|
|
124
|
if( @_ ) |
|
439
|
|
|
|
|
|
|
{ |
|
440
|
2
|
|
|
|
|
12
|
my $v = shift( @_ ); |
|
441
|
2
|
50
|
33
|
|
|
178
|
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
|
|
|
|
55
|
$v = join( '_', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
|
448
|
2
|
50
|
|
|
|
36
|
$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
|
|
|
|
21
|
return( $self->error( "No domain is set or it has disappeared!" ) ) if( !$self->{domain} ); |
|
455
|
2
|
|
|
|
|
36
|
$self->{locale} = $v; |
|
456
|
2
|
|
|
|
|
30
|
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
|
|
|
|
19
|
$self->textdomain( $self->{domain} ) unless( $caller eq 'Module::Generic::init' ); |
|
460
|
|
|
|
|
|
|
} |
|
461
|
41
|
|
|
|
|
177
|
return( $self->_set_get_scalar_as_object( 'locale' ) ); |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub locale_unix |
|
465
|
|
|
|
|
|
|
{ |
|
466
|
31
|
|
|
31
|
1
|
1421
|
my $self = shift( @_ ); |
|
467
|
31
|
|
66
|
|
|
112
|
my $loc = shift( @_ ) || $self->locale; |
|
468
|
|
|
|
|
|
|
# Only once |
|
469
|
31
|
50
|
|
|
|
2069
|
if( $loc =~ /^$LOCALE_RE$/ ) |
|
470
|
|
|
|
|
|
|
{ |
|
471
|
31
|
100
|
|
|
|
633
|
$loc = join( '_', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
|
472
|
31
|
100
|
|
|
|
197
|
$loc .= '.' . $+{locale_encoding} if( $+{locale_encoding} ); |
|
473
|
|
|
|
|
|
|
} |
|
474
|
31
|
|
|
|
|
148
|
return( $loc ); |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
sub locale_web |
|
478
|
|
|
|
|
|
|
{ |
|
479
|
10
|
|
|
10
|
1
|
28
|
my $self = shift( @_ ); |
|
480
|
10
|
|
33
|
|
|
44
|
my $loc = shift( @_ ) || $self->locale; |
|
481
|
|
|
|
|
|
|
# Only once |
|
482
|
10
|
50
|
|
|
|
278
|
if( $loc =~ /^$LOCALE_RE$/ ) |
|
483
|
|
|
|
|
|
|
{ |
|
484
|
10
|
100
|
|
|
|
176
|
$loc = join( '-', $+{locale_lang}, ( $+{locale_country} ? $+{locale_country} : () ) ); |
|
485
|
10
|
100
|
|
|
|
70
|
$loc .= '.' . $+{locale_encoding} if( $+{locale_encoding} ); |
|
486
|
|
|
|
|
|
|
} |
|
487
|
10
|
|
|
|
|
70
|
return( $loc ); |
|
488
|
|
|
|
|
|
|
} |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub ngettext |
|
491
|
|
|
|
|
|
|
{ |
|
492
|
2
|
|
|
2
|
1
|
988
|
my $self = shift( @_ ); |
|
493
|
2
|
|
|
|
|
10
|
my( $msgid, $msgidPlural, $count ) = @_; |
|
494
|
2
|
|
|
|
|
15
|
return( $self->dngettext( $self->domain, $msgid, $msgidPlural, $count ) ); |
|
495
|
|
|
|
|
|
|
} |
|
496
|
|
|
|
|
|
|
|
|
497
|
5
|
|
|
5
|
1
|
1485
|
sub path { return( shift->_set_get_file( 'path', @_ ) ); } |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub plural |
|
500
|
|
|
|
|
|
|
{ |
|
501
|
15
|
|
|
15
|
1
|
1512
|
my $self = shift( @_ ); |
|
502
|
15
|
50
|
|
|
|
51
|
if( @_ ) |
|
503
|
|
|
|
|
|
|
{ |
|
504
|
0
|
|
|
|
|
0
|
return( $self->_set_get_array_as_object( 'plural', @_ ) ); |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
else |
|
507
|
|
|
|
|
|
|
{ |
|
508
|
15
|
100
|
|
|
|
25
|
if( !scalar( @{$self->{plural}} ) ) |
|
|
15
|
|
|
|
|
53
|
|
|
509
|
|
|
|
|
|
|
{ |
|
510
|
1
|
|
|
|
|
5
|
$self->{plural} = $self->getPlural(); |
|
511
|
|
|
|
|
|
|
} |
|
512
|
15
|
|
|
|
|
82
|
return( $self->_set_get_array_as_object( 'plural' ) ); |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
|
|
516
|
1
|
|
|
1
|
1
|
39785
|
sub pluralForms { return( shift->_get_po->plural_forms ); } |
|
517
|
|
|
|
|
|
|
|
|
518
|
1
|
|
|
1
|
1
|
812
|
sub po_object { return( shift->_get_po ); } |
|
519
|
|
|
|
|
|
|
|
|
520
|
1
|
|
|
1
|
1
|
418
|
sub poRevisionDate { return( shift->_get_po->po_revision_date ); } |
|
521
|
|
|
|
|
|
|
|
|
522
|
1
|
|
|
1
|
1
|
1972
|
sub potCreationDate { return( shift->_get_po->pot_creation_date ); } |
|
523
|
|
|
|
|
|
|
|
|
524
|
1
|
|
|
1
|
1
|
1393
|
sub projectIdVersion { return( shift->_get_po->project_id_version ); } |
|
525
|
|
|
|
|
|
|
|
|
526
|
1
|
|
|
1
|
1
|
671
|
sub reportBugsTo { return( shift->_get_po->report_bugs_to ); } |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
sub textdomain |
|
529
|
|
|
|
|
|
|
{ |
|
530
|
2
|
|
|
2
|
1
|
9
|
my $self = shift( @_ ); |
|
531
|
2
|
|
50
|
|
|
14
|
my $dom = shift( @_ ) || return( $self->error( "No domain was provided." ) ); |
|
532
|
2
|
|
|
|
|
35
|
my $base = $self->path; |
|
533
|
2
|
|
|
|
|
1551
|
my $lang = $self->locale_unix; |
|
534
|
2
|
50
|
|
|
|
42
|
my $path_po = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.po" ); |
|
535
|
2
|
50
|
|
|
|
266621
|
my $path_json = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.json" ); |
|
536
|
2
|
50
|
|
|
|
266730
|
my $path_mo = $base->join( $base, $lang, ( $self->category ? $self->category : () ), "${dom}.mo" ); |
|
537
|
2
|
|
|
|
|
265299
|
my $file; |
|
538
|
|
|
|
|
|
|
my $po; |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
|
541
|
2
|
50
|
33
|
|
|
106
|
if( $self->use_json && $path_json->exists ) |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
{ |
|
543
|
2
|
|
|
|
|
1721
|
$file = $path_json; |
|
544
|
2
|
|
50
|
|
|
38
|
$po = Text::PO->new( domain => $dom, use_json => 1, debug => $self->debug ) || |
|
545
|
|
|
|
|
|
|
return( $self->pass_error( Text::PO->error ) ); |
|
546
|
2
|
50
|
|
|
|
44
|
$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
|
|
|
|
14
|
$L10N->{ $dom } = {} if( ref( $L10N->{ $dom } ) ne 'HASH' ); |
|
570
|
2
|
50
|
|
|
|
42
|
my $dict = $L10N->{ $dom }->{ $lang } = {} if( ref( $L10N->{ $dom }->{ $lang } ) ne 'HASH' ); |
|
571
|
2
|
|
|
|
|
53
|
$dict->{_po} = $po; |
|
572
|
|
|
|
|
|
|
$po->elements->foreach(sub |
|
573
|
|
|
|
|
|
|
{ |
|
574
|
18
|
|
|
18
|
|
1564
|
my $ref = shift( @_ ); |
|
575
|
18
|
|
|
|
|
97
|
$dict->{ $ref->{msgid} } = $ref; |
|
576
|
2
|
|
|
|
|
74
|
}); |
|
577
|
2
|
|
|
|
|
92
|
return( $self ); |
|
578
|
|
|
|
|
|
|
} |
|
579
|
|
|
|
|
|
|
|
|
580
|
3
|
|
|
3
|
1
|
912
|
sub use_json { return( shift->_set_get_boolean( 'use_json', @_ ) ); } |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub _get_days |
|
583
|
|
|
|
|
|
|
{ |
|
584
|
4
|
|
|
4
|
|
1632
|
my $self = shift( @_ ); |
|
585
|
4
|
|
|
|
|
13
|
my $locale = shift( @_ ); |
|
586
|
4
|
|
|
|
|
21
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
|
587
|
4
|
|
|
|
|
15
|
my $short = $self->new_array; |
|
588
|
4
|
|
|
|
|
78
|
my $long = $self->new_array; |
|
589
|
|
|
|
|
|
|
|
|
590
|
4
|
50
|
|
|
|
83
|
POSIX::setlocale( &POSIX::LC_ALL, $locale ) if( defined( $locale ) ); |
|
591
|
|
|
|
|
|
|
|
|
592
|
4
|
|
|
|
|
56
|
for (my $i = 1; $i <= 7; $i++) |
|
593
|
|
|
|
|
|
|
{ |
|
594
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::ABDAY_${i}"; |
|
595
|
28
|
|
|
|
|
129
|
my $const = I18N::Langinfo->can( "ABDAY_${i}" ); |
|
596
|
|
|
|
|
|
|
# $short->[$i-1] = langinfo( &$const ); |
|
597
|
28
|
|
|
|
|
133
|
$short->[$i-1] = langinfo( $const->() ); |
|
598
|
|
|
|
|
|
|
} |
|
599
|
4
|
|
|
|
|
13
|
for (my $i = 1; $i <= 7; $i++) |
|
600
|
|
|
|
|
|
|
{ |
|
601
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::DAY_${i}"; |
|
602
|
28
|
|
|
|
|
121
|
my $const = I18N::Langinfo->can( "DAY_${i}" ); |
|
603
|
|
|
|
|
|
|
# $long->[$i-1] = langinfo( &$const ); |
|
604
|
28
|
|
|
|
|
123
|
$long->[$i-1] = langinfo( $const->() ); |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
|
|
607
|
4
|
50
|
|
|
|
52
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
|
608
|
|
|
|
|
|
|
|
|
609
|
4
|
|
|
|
|
13
|
return( [ $short, $long ] ); |
|
610
|
|
|
|
|
|
|
} |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
sub _get_months |
|
613
|
|
|
|
|
|
|
{ |
|
614
|
2
|
|
|
2
|
|
814
|
my $self = shift( @_ ); |
|
615
|
2
|
|
|
|
|
6
|
my $locale = shift( @_ ); |
|
616
|
2
|
|
|
|
|
11
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
|
617
|
2
|
|
|
|
|
24
|
my $short = $self->new_array; |
|
618
|
2
|
|
|
|
|
42
|
my $long = $self->new_array; |
|
619
|
|
|
|
|
|
|
|
|
620
|
2
|
50
|
|
|
|
43
|
POSIX::setlocale( &POSIX::LC_ALL, $locale ) if( defined( $locale ) ); |
|
621
|
|
|
|
|
|
|
|
|
622
|
2
|
|
|
|
|
28
|
for( my $i = 1; $i <= 12; $i++ ) |
|
623
|
|
|
|
|
|
|
{ |
|
624
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::ABMON_${i}"; |
|
625
|
|
|
|
|
|
|
# $short->[$i-1] = langinfo( &$const ); |
|
626
|
24
|
|
|
|
|
150
|
my $const = I18N::Langinfo->can( "ABMON_${i}" ); |
|
627
|
24
|
|
|
|
|
107
|
$short->[$i-1] = langinfo( $const->() ); |
|
628
|
|
|
|
|
|
|
} |
|
629
|
2
|
|
|
|
|
13
|
for( my $i = 1; $i <= 12; $i++ ) |
|
630
|
|
|
|
|
|
|
{ |
|
631
|
|
|
|
|
|
|
# my $const = "I18N::Langinfo::MON_${i}"; |
|
632
|
|
|
|
|
|
|
# $long->[$i-1] = langinfo( &$const ); |
|
633
|
24
|
|
|
|
|
121
|
my $const = I18N::Langinfo->can( "MON_${i}" ); |
|
634
|
24
|
|
|
|
|
104
|
$long->[$i-1] = langinfo( $const->() ); |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
|
|
637
|
2
|
50
|
|
|
|
30
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
|
638
|
|
|
|
|
|
|
|
|
639
|
2
|
|
|
|
|
18
|
return( [ $short, $long ] ); |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub _get_numeric_dict |
|
643
|
|
|
|
|
|
|
{ |
|
644
|
2
|
|
|
2
|
|
805
|
my $self = shift( @_ ); |
|
645
|
2
|
|
|
|
|
4
|
my $locale = shift( @_ ); |
|
646
|
2
|
|
|
|
|
12
|
my $oldlocale = POSIX::setlocale( &POSIX::LC_ALL ); |
|
647
|
2
|
50
|
|
|
|
20
|
POSIX::setlocale( &POSIX::LC_ALL, $locale) if( defined( $locale ) ); |
|
648
|
2
|
|
|
|
|
35
|
my $lconv = POSIX::localeconv(); |
|
649
|
2
|
50
|
|
|
|
26
|
POSIX::setlocale( &POSIX::LC_ALL, $oldlocale) if( defined( $locale ) ); |
|
650
|
2
|
|
|
|
|
14
|
my $def = $self->new_hash; |
|
651
|
|
|
|
|
|
|
@$def{qw( currency decimal int_currency negative_sign thousand precision )} = |
|
652
|
2
|
|
|
|
|
1019
|
@$lconv{qw( currency_symbol decimal_point int_curr_symbol negative_sign thousands_sep frac_digits )}; |
|
653
|
2
|
|
|
2
|
|
26
|
use utf8; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
20
|
|
|
654
|
2
|
50
|
33
|
|
|
202
|
$def->{currency} = '€' if( CORE::exists( $def->{currency} ) && defined( $def->{currency} ) && $def->{currency} eq 'EUR' ); |
|
|
|
|
33
|
|
|
|
|
|
655
|
2
|
0
|
33
|
|
|
98
|
$lconv->{currency_symbol} = '€' if( CORE::exists( $lconv->{currency_symbol} ) && defined( $lconv->{currency_symbol} ) && $lconv->{currency_symbol} eq 'EUR' ); |
|
|
|
|
33
|
|
|
|
|
|
656
|
2
|
50
|
33
|
|
|
6
|
$lconv->{grouping} = unpack( "C*", $lconv->{grouping} ) if( CORE::exists( $lconv->{grouping} ) && defined( $lconv->{grouping} ) ); |
|
657
|
2
|
50
|
33
|
|
|
8
|
$lconv->{mon_grouping} = unpack( "C*", $lconv->{mon_grouping} ) if( CORE::exists( $lconv->{mon_grouping} ) && defined( $lconv->{mon_grouping} ) ); |
|
658
|
2
|
|
|
|
|
7
|
$lconv = $self->new_hash( $lconv ); |
|
659
|
2
|
|
|
|
|
1023
|
return( [ $def, $lconv ] ); |
|
660
|
|
|
|
|
|
|
} |
|
661
|
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
sub _get_po |
|
663
|
|
|
|
|
|
|
{ |
|
664
|
15
|
|
|
15
|
|
47
|
my $self = shift( @_ ); |
|
665
|
15
|
|
|
|
|
55
|
my $hash = $self->getDomainHash({ locale => $self->locale }); |
|
666
|
15
|
|
|
|
|
177
|
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
|
|
484
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
45
|
|
|
676
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
70
|
|
|
677
|
2
|
|
|
2
|
|
12
|
use parent qw( Module::Generic ); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
12
|
|
|
678
|
2
|
|
|
2
|
|
158
|
use vars qw( $VERSION ); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
141
|
|
|
679
|
2
|
|
|
2
|
|
184
|
our $VERSION = 'v0.1.0'; |
|
680
|
|
|
|
|
|
|
use overload ( |
|
681
|
|
|
|
|
|
|
'""' => 'as_string', |
|
682
|
0
|
|
|
0
|
|
0
|
'bool' => sub{1}, |
|
683
|
2
|
|
|
|
|
26
|
fallback => 1, |
|
684
|
2
|
|
|
2
|
|
13
|
); |
|
|
2
|
|
|
|
|
4
|
|
|
685
|
|
|
|
|
|
|
}; |
|
686
|
|
|
|
|
|
|
|
|
687
|
2
|
|
|
2
|
|
33
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
40
|
|
|
688
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
351
|
|
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
sub init |
|
691
|
|
|
|
|
|
|
{ |
|
692
|
4
|
|
|
4
|
|
364
|
my $self = shift( @_ ); |
|
693
|
4
|
|
|
|
|
9
|
my $value = shift( @_ ); |
|
694
|
4
|
|
|
|
|
14
|
my $locale = shift( @_ ); |
|
695
|
4
|
|
|
|
|
61
|
$self->{locale} = $locale; |
|
696
|
4
|
|
|
|
|
22
|
$self->{value} = $value; |
|
697
|
4
|
|
|
|
|
32
|
$self->SUPER::init( @_ ); |
|
698
|
4
|
|
|
|
|
254
|
return( $self ); |
|
699
|
|
|
|
|
|
|
} |
|
700
|
|
|
|
|
|
|
|
|
701
|
4
|
|
|
4
|
|
1640
|
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
|
|
33
|
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 |