← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/I18N.pm
StatementsExecuted 31 statements in 1.55ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
111478µs540µsFoswiki::I18N::::newFoswiki::I18N::new
11114µs27µsFoswiki::I18N::::BEGIN@13Foswiki::I18N::BEGIN@13
11111µs126µsFoswiki::I18N::::BEGIN@16Foswiki::I18N::BEGIN@16
11110µs36µsFoswiki::I18N::::BEGIN@15Foswiki::I18N::BEGIN@15
11110µs14µsFoswiki::I18N::::BEGIN@14Foswiki::I18N::BEGIN@14
1116µs6µsFoswiki::I18N::::finishFoswiki::I18N::finish
1116µs6µsFoswiki::I18N::::BEGIN@18Foswiki::I18N::BEGIN@18
1116µs6µsFoswiki::I18N::::BEGIN@95Foswiki::I18N::BEGIN@95
0000s0sFoswiki::I18N::::__ANON__[:219]Foswiki::I18N::__ANON__[:219]
0000s0sFoswiki::I18N::::__ANON__[:277]Foswiki::I18N::__ANON__[:277]
0000s0sFoswiki::I18N::::__ANON__[:286]Foswiki::I18N::__ANON__[:286]
0000s0sFoswiki::I18N::::_add_languageFoswiki::I18N::_add_language
0000s0sFoswiki::I18N::::_discover_languagesFoswiki::I18N::_discover_languages
0000s0sFoswiki::I18N::::_loadLexiconFoswiki::I18N::_loadLexicon
0000s0sFoswiki::I18N::::_normalize_language_tagFoswiki::I18N::_normalize_language_tag
0000s0sFoswiki::I18N::::available_languagesFoswiki::I18N::available_languages
0000s0sFoswiki::I18N::::enabled_languagesFoswiki::I18N::enabled_languages
0000s0sFoswiki::I18N::::languageFoswiki::I18N::language
0000s0sFoswiki::I18N::::maketextFoswiki::I18N::maketext
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::I18N
6
7Support for strings translation and language detection.
8
9=cut
10
11package Foswiki::I18N;
12
13229µs240µs
# spent 27µs (14+13) within Foswiki::I18N::BEGIN@13 which was called: # once (14µs+13µs) by Foswiki::i18n at line 13
use strict;
# spent 27µs making 1 call to Foswiki::I18N::BEGIN@13 # spent 13µs making 1 call to strict::import
14224µs218µs
# spent 14µs (10+4) within Foswiki::I18N::BEGIN@14 which was called: # once (10µs+4µs) by Foswiki::i18n at line 14
use warnings;
# spent 14µs making 1 call to Foswiki::I18N::BEGIN@14 # spent 4µs making 1 call to warnings::import
15229µs261µs
# spent 36µs (10+26) within Foswiki::I18N::BEGIN@15 which was called: # once (10µs+26µs) by Foswiki::i18n at line 15
use Assert;
# spent 36µs making 1 call to Foswiki::I18N::BEGIN@15 # spent 26µs making 1 call to Exporter::import
16252µs2241µs
# spent 126µs (11+115) within Foswiki::I18N::BEGIN@16 which was called: # once (11µs+115µs) by Foswiki::i18n at line 16
use Error qw(:try);
# spent 126µs making 1 call to Foswiki::I18N::BEGIN@16 # spent 115µs making 1 call to Error::import
17
18
# spent 6µs within Foswiki::I18N::BEGIN@18 which was called: # once (6µs+0s) by Foswiki::i18n at line 23
BEGIN {
1915µs if ( $Foswiki::cfg{UseLocale} ) {
20 require locale;
21 import locale();
22 }
231495µs16µs}
# spent 6µs making 1 call to Foswiki::I18N::BEGIN@18
24
251100nsour $initialised;
261300nsour @initErrors;
27
28=begin TML
29
30---++ ClassMethod available_languages
31
32Lists languages tags for languages available at Foswiki installation. Returns a
33list containing the tags of the available languages.
34
35__Note__: the languages available to users are determined in the =configure=
36interface.
37
38=cut
39
40sub available_languages {
41
42 my @available;
43
44 while ( my ( $langCode, $langOptions ) =
45 each %{ $Foswiki::cfg{Languages} } )
46 {
47 if ( $langOptions->{Enabled} ) {
48 push( @available, _normalize_language_tag($langCode) );
49 }
50 }
51
52 return @available;
53}
54
55# utility function: normalize language tags like ab_CD to ab-cd
56# also renove any character there is not a letter [a-z] or a hyphen.
57sub _normalize_language_tag {
58 my $tag = shift;
59 $tag = lc( $tag || '' );
60 $tag =~ s/\_/-/g;
61 $tag =~ s/[^a-z-]//g;
62 return $tag;
63}
64
65sub _loadLexicon {
66 my ( $lang, $dir ) = @_;
67
68 $dir ||= $Foswiki::cfg{LocalesDir};
69
70 my $langFile = "$dir/$lang.po";
71
72 #print STDERR "langFile=$langFile\n";
73
74 # Use the compressed version if it exists
75 if ( $langFile =~ m/^(.*)\.po$/
76 && -f "$1.mo" )
77 {
78 $langFile = "$1.mo";
79 }
80 if ( -f $langFile ) {
81 unless (
82 eval {
83 Locale::Maketext::Lexicon->import(
84 { _decode => 1, $lang => [ Gettext => $langFile ] } );
85 1;
86 }
87 )
88 {
89 push( @initErrors, "I18N - Error loading language $lang: $@\n" );
90 }
91 }
92}
93
94# initialisation block
95
# spent 6µs within Foswiki::I18N::BEGIN@95 which was called: # once (6µs+0s) by Foswiki::i18n at line 148
BEGIN {
96
97 # we only need to proceed if user wants internationalisation support
9816µs return unless $Foswiki::cfg{UserInterfaceInternationalisation};
99
100 # no languages enabled is the same as disabling
101 # {UserInterfaceInternationalisation}
102 my @languages = available_languages();
103 return unless ( scalar(@languages) );
104
105 # we first assume it's ok
106 $initialised = 1;
107
108 eval "use Locale::Maketext ()";
109 if ($@) {
110 $initialised = 0;
111 push( @initErrors,
112 "I18N: Couldn't load required perl module Locale::Maketext: "
113 . $@
114 . "\nInstall the module or turn off {UserInterfaceInternationalisation}"
115 );
116 }
117 else {
118 @Foswiki::I18N::ISA = ('Locale::Maketext');
119 }
120
121 unless ( $Foswiki::cfg{LocalesDir} && -e $Foswiki::cfg{LocalesDir} ) {
122 push( @initErrors,
123'I18N: {LocalesDir} not configured. Define it or turn off {UserInterfaceInternationalisation}'
124 );
125 $initialised = 0;
126 }
127
128 # dynamically build languages to be loaded according to admin-enabled
129 # languages.
130 eval "use Locale::Maketext::Lexicon{ en => [ 'Auto' ] } ;";
131 if ($@) {
132 $initialised = 0;
133 push( @initErrors,
134 "I18N - Couldn't load default English messages: $@\n"
135 . "Install Locale::Maketext::Lexicon or turn off {UserInterfaceInternationalisation}"
136 );
137 }
138
139 opendir( my $dh, "$Foswiki::cfg{LocalesDir}/" ) || next;
140 my @subDirs =
141 grep { !/^\./ && -d "$Foswiki::cfg{LocalesDir}/$_" } readdir $dh;
142 closedir $dh;
143
144 foreach my $lang (@languages) {
145 _loadLexicon($lang);
146 _loadLexicon( $lang, "$Foswiki::cfg{LocalesDir}/$_" ) foreach @subDirs;
147 }
1481803µs16µs}
# spent 6µs making 1 call to Foswiki::I18N::BEGIN@95
149
150=begin TML
151
152---++ ClassMethod new ( $session )
153
154Constructor. Gets the language object corresponding to the current users
155language. If $session is not a Foswiki object reference, just calls
156Local::Maketext::new (the superclass constructor)
157
158=cut
159
160
# spent 540µs (478+62) within Foswiki::I18N::new which was called: # once (478µs+62µs) by Foswiki::i18n at line 2344 of /var/www/foswikidev/core/lib/Foswiki.pm
sub new {
1611700ns my $class = shift;
1621500ns my ($session) = @_;
163
16418µs11µs unless ( ref($session) && $session->isa('Foswiki') ) {
# spent 1µs making 1 call to UNIVERSAL::isa
165
166 # it's recursive
167 return $class->SUPER::new(@_);
168 }
169
1701300ns if (@initErrors) {
171 foreach my $error (@initErrors) {
172 $session->logger->log( $initialised ? 'warning' : 'error', $error );
173 }
174 }
175
176 # guesses the language from the CGI environment
177 # TODO:
178 # web/user/session setting must override the language detected from the
179 # browser.
1801100ns my $this;
1811400ns if ($initialised) {
182 $session->enterContext('i18n_enabled');
183 my $userLanguage = _normalize_language_tag(
184 $session->{prefs}->getPreference('LANGUAGE') );
185 if ($userLanguage) {
186 $this = Foswiki::I18N->get_handle($userLanguage);
187 }
188 else {
189 $this = Foswiki::I18N->get_handle();
190 }
191 }
192 else {
193171µs require Foswiki::I18N::Fallback;
194
19513µs18µs $this = new Foswiki::I18N::Fallback();
# spent 8µs making 1 call to Foswiki::I18N::Fallback::new
196
197 # we couldn't initialise 'optional' I18N infrastructure, warn that we
198 # can only use English if I18N has been requested with configure
1991900ns $session->logger->log( 'warning',
200 'Could not load I18N infrastructure; falling back to English' )
201 if $Foswiki::cfg{UserInterfaceInternationalisation};
202 }
203
204 # keep a reference to the session object
2051700ns $this->{session} = $session;
206
207 # languages we know about
20812µs $this->{enabled_languages} = { en => 'English' };
2091400ns $this->{checked_enabled} = undef;
210
211 # what to do with failed translations (only needed when already initialised
212 # and language is not English);
2131100ns if ( $initialised and ( $this->language ne 'en' ) ) {
214 my $fallback_handle = Foswiki::I18N->get_handle('en');
215 $this->fail_with(
216 sub {
217 shift; # get rid of the handle
218 return $fallback_handle->maketext(@_);
219 }
220 );
221 }
222
223 # finally! :-p
22413µs return $this;
225}
226
227=begin TML
228
229---++ ObjectMethod finish()
230Break circular references.
231
232=cut
233
234# Note to developers; please undef *all* fields in the object explicitly,
235# whether they are references or not. That way this method is "golden
236# documentation" of the live fields in the object.
237
# spent 6µs within Foswiki::I18N::finish which was called: # once (6µs+0s) by Foswiki::I18N::Fallback::finish at line 31 of /var/www/foswikidev/core/lib/Foswiki/I18N/Fallback.pm
sub finish {
2381700ns my $this = shift;
23913µs undef $this->{enabled_languages};
2401500ns undef $this->{checked_enabled};
24115µs undef $this->{session};
242}
243
244=begin TML
245
246---++ ObjectMethod maketext( $text ) -> $translation
247
248Translates the given string (assumed to be written in English) into the
249current language, as detected in the constructor, and converts it into
250a binary UTF-8 string.
251
252Wraps around Locale::Maketext's maketext method, adding charset conversion
253and checking.
254
255Return value: translated string, or the argument itself if no translation is
256found for thet argument.
257
258=cut
259
260sub maketext {
261 my ( $this, $text, @args ) = @_;
262
263 if ( $text =~ m/^_/ && $text ne '_language_name' ) {
264 require CGI;
265 import CGI();
266
267 return CGI::span(
268 { -class => 'foswikiAlert' },
269 "Error: MAKETEXT arguments can't start with an underscore (\"_\")."
270 );
271 }
272
273 my $result = '';
274 try {
275 $result = $this->SUPER::maketext( $text, @args );
276 return $result;
277 }
278 catch Error with {
279 my $e = shift;
280 print STDERR
281 "#### Error: MAKETEXT - String translation failed for \"$text\". "
282 . $e->stringify()
283 if DEBUG;
284 return
285"<span class='foswikiAlert'>ERROR: Translation failed, see server error log.</span>";
286 }
287}
288
289=begin TML
290
291---++ ObjectMethod language() -> $language_tag
292
293Indicates the language tag of the current user's language, as detected from the
294information sent by the browser. Returns the empty string if the language
295could not be determined.
296
297=cut
298
299sub language {
300 my $this = shift;
301
302 return $this->language_tag();
303}
304
305=begin TML
306
307---++ ObjectMethod enabled_languages() -> %languages
308
309Returns an array with language tags as keys and language (native) names as
310values, for all the languages enabled in this site. Useful for
311listing available languages to the user.
312
313=cut
314
315sub enabled_languages {
316 my $this = shift;
317
318 unless ( $this->{checked_enabled} ) {
319 _discover_languages($this);
320 }
321
322 $this->{checked_enabled} = 1;
323 return $this->{enabled_languages};
324
325}
326
327# discovers the available language.
328sub _discover_languages {
329 my $this = shift;
330 my $cache_open = 0;
331
332 #use the cache, if available
333 if ( open LANGUAGE, '<', "$Foswiki::cfg{WorkingDir}/languages.cache" ) {
334 $cache_open = 1;
335 foreach my $line ( map { Foswiki::decode_utf8($_) } <LANGUAGE> ) {
336 my ( $key, $name ) = split( '=', $line );
337
338 # Filter on enabled languages
339 next
340 unless ( $Foswiki::cfg{Languages}{$key}
341 && $Foswiki::cfg{Languages}{$key}{Enabled} );
342 chop($name);
343 _add_language( $this, $key, $name );
344 }
345 }
346 else {
347
348 # Rebuild the cache, filtering on enabled languages.
349 $cache_open =
350 open( LANGUAGE, '>', "$Foswiki::cfg{WorkingDir}/languages.cache" );
351 foreach my $tag ( available_languages() ) {
352 my $h = Foswiki::I18N->get_handle($tag);
353 my $name = eval { $h->maketext("_language_name") } or next;
354 print LANGUAGE Foswiki::encode_utf8("$tag=$name\n") if $cache_open;
355
356 # Filter on enabled languages
357 next
358 unless ( $Foswiki::cfg{Languages}{$tag}
359 && $Foswiki::cfg{Languages}{$tag}{Enabled} );
360 _add_language( $this, $tag, $name );
361 }
362 }
363
364 close LANGUAGE if $cache_open;
365 $this->{checked_enabled} = 1;
366
367}
368
369# private utility method: add a pair tag/language name
370sub _add_language {
371 my ( $this, $tag, $name ) = @_;
372 $this->{enabled_languages}->{$tag} = $name;
373}
374
37513µs1;
376__END__