source: main/trunk/greenstone2/perllib/gsprintf.pm@ 31724

Last change on this file since 31724 was 31419, checked in by kjdon, 7 years ago

new arg to lookup_string: pass in a 1 if you want the output to be perl internal (unicode-aware) strings, rather than utf8. We want this for eg when we get the 'this document has no text' message, its going into doc_obj which is using perl strings not utf8. Strangely, the few places where we are calling lookup_string for this purpose, it is already passing in an extra 1 arg. do do do do...

  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1###########################################################################
2#
3# gsprintf.pm --
4# A component of the Greenstone digital library software
5# from the New Zealand Digital Library Project at the
6# University of Waikato, New Zealand.
7#
8# Copyright (C) 1999 New Zealand Digital Library Project
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23#
24###########################################################################
25use strict;
26no strict 'refs';
27
28package gsprintf;
29require Exporter;
30@gsprintf::ISA=qw(Exporter);
31
32use Encode;
33
34use unicode;
35use util;
36use FileUtils;
37
38@gsprintf::EXPORT_OK = qw(gsprintf); # functions we can export into namespace
39
40
41# Language-specific resource bundle
42my %specialresourcebundle = ();
43our $specialoutputencoding; # our, so that it can be changed outside.
44
45# Default resource bundle
46my %defaultresourcebundle;
47my $defaultoutputencoding;
48
49# English resource bundle
50my %englishresourcebundle;
51my $englishoutputencoding;
52
53# Ignore the OutputEncoding strings in the resource bundles and output all text in UTF-8
54my $outputstringsinUTF8 = 0;
55my $freetext_xml_mode = 0;
56
57
58sub make_freetext_xml_safe
59{
60 my ($text) = @_;
61
62 $text =~ s/\&/&/g;
63 $text =~ s/\"/"/g;
64 $text =~ s/\</&lt;/g;
65 $text =~ s/\>/&gt;/g;
66
67 return $text;
68}
69
70
71sub gsprintf
72{
73 my ($handle, $text_string, @text_arguments) = @_;
74
75 # Return unless the required arguments were supplied
76 return unless (defined($handle) && defined($text_string));
77
78 # Look up all the strings in the dictionary
79 $text_string =~ s/(\{[^\}]+\})/&lookup_string($1)/eg;
80
81 # Resolve the string arguments using sprintf, then write out to the handle
82 my $text_string_resolved = sprintf($text_string, @text_arguments);
83
84 if ($freetext_xml_mode) {
85 $text_string_resolved = make_freetext_xml_safe($text_string_resolved);
86 }
87
88 print $handle $text_string_resolved;
89}
90
91
92
93sub lookup_string
94{
95 my ($stringkey, $native_perl) = @_;
96
97 if (!defined $native_perl || $native_perl != 1) {
98 $native_perl = 0;
99 }
100 return "" unless defined $stringkey;
101 # Try the language-specific resource bundle first
102 my $utf8string = $specialresourcebundle{$stringkey};
103 my $outputencoding = $specialoutputencoding;
104
105 # Try the default resource bundle next
106 if (!defined($utf8string)) {
107 # Load the default resource bundle if it is not already loaded
108 &load_default_resource_bundle() if (!%defaultresourcebundle);
109
110 $utf8string = $defaultresourcebundle{$stringkey};
111 $outputencoding = $defaultoutputencoding;
112 }
113
114 # Try the English resource bundle last
115 if (!defined($utf8string)) {
116 # Load the English resource bundle if it is not already loaded
117 &load_english_resource_bundle() if (!%englishresourcebundle);
118
119 $utf8string = $englishresourcebundle{$stringkey};
120 $outputencoding = $englishoutputencoding;
121 }
122
123 # No matching string was found, so just return the key
124 if (!defined($utf8string)) {
125 return $stringkey;
126 }
127
128 if ($native_perl ==1) {
129 # decode the utf8 string to perl internal format
130 return decode("utf8", $utf8string);
131 }
132
133 # Return the utf8 string if our output encoding is utf8
134 if (!defined($outputencoding) || $outputstringsinUTF8
135 || $outputencoding eq "utf8") {
136 return $utf8string;
137 }
138
139 # If an 8-bit output encoding has been defined, encode the string appropriately
140 my $encoded=unicode::unicode2singlebyte(&unicode::utf82unicode($utf8string), $outputencoding);
141
142 # If we successfully encoded it, return it
143 if ($encoded) { return $encoded }
144
145 # Otherwise, we can't convert to the requested encoding. return the utf8?
146 $specialoutputencoding='utf8';
147 return $utf8string;
148}
149
150
151sub load_language_specific_resource_bundle
152{
153 my $language = shift(@_);
154
155 # Read the specified resource bundle
156 my $resourcebundlename = "strings_" . $language . ".properties";
157
158 %specialresourcebundle
159 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
160 return if (!%specialresourcebundle);
161
162 # Read the output encoding to use from the resource bundle
163 if ($ENV{'GSDLOS'} =~ /windows/) {
164 $specialoutputencoding = $specialresourcebundle{"{OutputEncoding.windows}"};
165 }
166 else {
167 # see if there is an encoding set in the appropriate locale env var
168
169 foreach my $envvar ('LC_ALL', 'LANG') {
170 if (!exists $ENV{$envvar}) { next }
171 my $locale=$ENV{$envvar};
172 if ($locale !~ /^\w+\.(.+)$/) { next }
173 my $enc=lc($1);
174 $enc =~ s/-/_/g;
175 if ($enc eq 'utf_8') { $enc='utf8' } # normalise to this name
176 $specialoutputencoding = $enc;
177 return;
178 }
179 $specialoutputencoding = $specialresourcebundle{"{OutputEncoding.unix}"};
180 }
181}
182
183
184sub load_default_resource_bundle
185{
186 # Read the default resource bundle
187 my $resourcebundlename = "strings.properties";
188
189 %defaultresourcebundle
190 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
191 if (!%defaultresourcebundle) {
192 # $! will still have the error value for the last failed syscall
193
194 my $error_message = "$! $resourcebundlename\n";
195
196 if ($freetext_xml_mode) {
197 $error_message = make_freetext_xml_safe($error_message);
198 }
199
200 print STDERR $error_message;
201
202 # set something so we don't bother trying to load it again
203 $defaultresourcebundle{0}=undef;
204 return;
205 }
206
207 # Read the output encoding to use from the resource bundle
208 if ($ENV{'GSDLOS'} =~ /windows/) {
209 $defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.windows}"};
210 }
211 else {
212 $defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.unix}"};
213 }
214}
215
216
217sub load_english_resource_bundle
218{
219 # Ensure the English resource bundle hasn't already been loaded
220 if (%specialresourcebundle && $specialresourcebundle{"{Language.code}"} eq "en") {
221 %englishresourcebundle = %specialresourcebundle;
222 $englishoutputencoding = $specialoutputencoding;
223 }
224
225 if ($defaultresourcebundle{"{Language.code}"} &&
226 $defaultresourcebundle{"{Language.code}"} eq "en") {
227 %englishresourcebundle = %defaultresourcebundle;
228 $englishoutputencoding = $defaultoutputencoding;
229 }
230
231 # Read the English resource bundle
232 my $resourcebundlename = "strings_en.properties";
233
234 %englishresourcebundle
235 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
236 return if (!%englishresourcebundle);
237
238 # Read the output encoding to use from the resource bundle
239 if ($ENV{'GSDLOS'} =~ /windows/) {
240 $englishoutputencoding = $englishresourcebundle{"{OutputEncoding.windows}"};
241 }
242 else {
243 $englishoutputencoding = $englishresourcebundle{"{OutputEncoding.unix}"};
244 }
245}
246
247
248sub read_resource_bundle_and_extensions
249{
250 my ($bundle_base,$primary_dir,$resourcename) = @_;
251
252 my $primary_resourcebundlefile
253 = &FileUtils::filenameConcatenate($bundle_base,$primary_dir,$resourcename);
254
255 my $resourcebundle = read_resource_bundle($primary_resourcebundlefile);
256 return if (!defined $resourcebundle);
257
258 if (defined $ENV{'GSDLEXTS'}) {
259 my @extensions = split(/:/,$ENV{'GSDLEXTS'});
260 foreach my $e (@extensions) {
261 my $ext_base
262 = &FileUtils::filenameConcatenate($bundle_base,"ext",$e);
263
264 my $ext_resourcebundlefile
265 = &FileUtils::filenameConcatenate($ext_base,$primary_dir,$resourcename);
266
267 # can ignore return value (will be same reference to $resourcebundle)
268 read_resource_bundle($ext_resourcebundlefile,$resourcebundle);
269 }
270 }
271 if (defined $ENV{'GSDL3EXTS'}) {
272 my @extensions = split(/:/,$ENV{'GSDL3EXTS'});
273 foreach my $e (@extensions) {
274 my $ext_base
275 = &FileUtils::filenameConcatenate($ENV{'GSDL3SRCHOME'},"ext",$e);
276
277 my $ext_resourcebundlefile
278 = &FileUtils::filenameConcatenate($ext_base,$primary_dir,$resourcename);
279
280 # can ignore return value (will be same reference to $resourcebundle)
281 read_resource_bundle($ext_resourcebundlefile,$resourcebundle);
282 }
283 }
284
285 return %$resourcebundle;
286}
287
288
289sub read_resource_bundle
290{
291 my ($resourcebundlefilepath,$resourcebundle) = @_;
292
293 if (!open(RESOURCE_BUNDLE, "<$resourcebundlefilepath")) {
294 # When called for the first time (primary resource), $resourcebundle
295 # is not defined (=undef). If the file does not exist, then we return
296 # this 'undef' to signal it was not found
297 # For an extension resource bundle, if it does not exist this
298 # is not so serious (in fact quite likely) => return what we
299 # have built up so far
300
301 return $resourcebundle;
302 }
303
304 if (!defined $resourcebundle) {
305 # resource files exists, so exect some content to be stored
306 $resourcebundle = {};
307 }
308
309 # Load this resource bundle
310 my @resourcebundlelines = <RESOURCE_BUNDLE>;
311 close(RESOURCE_BUNDLE);
312
313 # Parse the resource bundle
314
315 foreach my $line (@resourcebundlelines) {
316 # Remove any trailing whitespace
317 $line =~ s/(\s*)$//;
318
319 # Ignore comments and empty lines
320 if ($line !~ /^\#/ && $line ne "") {
321 # Parse key (everything up to the first colon)
322 if ($line =~ m/^([^:]+):(.+)$/) {
323 my $linekey = "{" . $1 . "}";
324 my $linetext = $2;
325 $linetext =~ s/(\s*)\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d).*$//i;
326
327 # Map key to text
328 $resourcebundle->{$linekey} = $linetext;
329 }
330 }
331 }
332
333 return $resourcebundle;
334}
335
336
337sub set_print_freetext_for_xml
338{
339 $freetext_xml_mode = 1;
340}
341
342sub set_print_xml_tags
343{
344 $freetext_xml_mode = 0;
345}
346
347sub output_strings_in_UTF8
348{
349 $outputstringsinUTF8 = 1;
350}
351
352
353sub debug_unicode_string
354{
355 join("",
356 map { $_ > 255 ? # if wide character...
357 sprintf("\\x{%04X}", $_) : # \x{...}
358 chr($_)
359 } unpack("U*", $_[0])); # unpack Unicode characters
360}
361
362
3631;
Note: See TracBrowser for help on using the repository browser.