gettext: Perl Pitfalls
1
1 15.5.18.9 Bugs, Pitfalls, And Things That Do Not Work
1 .....................................................
1
1 The foregoing sections should have proven that ‘xgettext’ is quite
1 smart in extracting translatable strings from Perl sources. Yet, some
1 more or less exotic constructs that could be expected to work, actually
1 do not work.
1
1 One of the more relevant limitations can be found in the
1 implementation of variable interpolation inside quoted strings. Only
1 simple hash lookups can be used there:
1
1 print <<EOF;
1 $gettext{"The dot operator"
1 . " does not work"
1 . "here!"}
1 Likewise, you cannot @{[ gettext ("interpolate function calls") ]}
1 inside quoted strings or quote-like expressions.
1 EOF
1
1 This is valid Perl code and will actually trigger invocations of the
1 ‘gettext’ function at runtime. Yet, the Perl parser in ‘xgettext’ will
1 fail to recognize the strings. A less obvious example can be found in
1 the interpolation of regular expressions:
1
1 s/<!--START_OF_WEEK-->/gettext ("Sunday")/e;
1
1 The modifier ‘e’ will cause the substitution to be interpreted as an
1 evaluable statement. Consequently, at runtime the function ‘gettext()’
1 is called, but again, the parser fails to extract the string “Sunday”.
1 Use a temporary variable as a simple workaround if you really happen to
1 need this feature:
1
1 my $sunday = gettext "Sunday";
1 s/<!--START_OF_WEEK-->/$sunday/;
1
1 Hash slices would also be handy but are not recognized:
1
1 my @weekdays = @gettext{'Sunday', 'Monday', 'Tuesday', 'Wednesday',
1 'Thursday', 'Friday', 'Saturday'};
1 # Or even:
1 @weekdays = @gettext{qw (Sunday Monday Tuesday Wednesday Thursday
1 Friday Saturday) };
1
1 This is perfectly valid usage of the tied hash ‘%gettext’ but the
1 strings are not recognized and therefore will not be extracted.
1
1 Another caveat of the current version is its rudimentary support for
1 non-ASCII characters in identifiers. You may encounter serious problems
1 if you use identifiers with characters outside the range of ’A’-’Z’,
1 ’a’-’z’, ’0’-’9’ and the underscore ’_’.
1
1 Maybe some of these missing features will be implemented in future
1 versions, but since you can always make do without them at minimal
1 effort, these todos have very low priority.
1
1 A nasty problem are brace format strings that already contain braces
1 as part of the normal text, for example the usage strings typically
1 encountered in programs:
1
1 die "usage: $0 {OPTIONS} FILENAME...\n";
1
1 If you want to internationalize this code with Perl brace format
1 strings, you will run into a problem:
1
1 die __x ("usage: {program} {OPTIONS} FILENAME...\n", program => $0);
1
1 Whereas ‘{program}’ is a placeholder, ‘{OPTIONS}’ is not and should
1 probably be translated. Yet, there is no way to teach the Perl parser
1 in ‘xgettext’ to recognize the first one, and leave the other one alone.
1
1 There are two possible work-arounds for this problem. If you are
1 sure that your program will run under Perl 5.8.0 or newer (these Perl
1 versions handle positional parameters in ‘printf()’) or if you are sure
1 that the translator will not have to reorder the arguments in her
1 translation – for example if you have only one brace placeholder in your
1 string, or if it describes a syntax, like in this one –, you can mark
1 the string as ‘no-perl-brace-format’ and use ‘printf()’:
1
1 # xgettext: no-perl-brace-format
1 die sprintf ("usage: %s {OPTIONS} FILENAME...\n", $0);
1
1 If you want to use the more portable Perl brace format, you will have
1 to do put placeholders in place of the literal braces:
1
1 die __x ("usage: {program} {[}OPTIONS{]} FILENAME...\n",
1 program => $0, '[' => '{', ']' => '}');
1
1 Perl brace format strings know no escaping mechanism. No matter how
1 this escaping mechanism looked like, it would either give the programmer
1 a hard time, make translating Perl brace format strings heavy-going, or
1 result in a performance penalty at runtime, when the format directives
1 get executed. Most of the time you will happily get along with
1 ‘printf()’ for this special case.
1