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

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

let properties files have \n and \t in them to represent newlines and tabs

  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 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 _gsprintf($handle, $text_string, 0, @text_arguments);
75}
76
77sub gsprintf_multiline
78{
79 my ($handle, $text_string, @text_arguments) = @_;
80 _gsprintf($handle, $text_string, 1, @text_arguments);
81}
82
83sub _gsprintf
84{
85 my ($handle, $text_string, $multiline, @text_arguments) = @_;
86
87 # Return unless the required arguments were supplied
88 return unless (defined($handle) && defined($text_string));
89
90 # Look up all the strings in the dictionary
91 $text_string =~ s/(\{[^\}]+\})/&lookup_string($1)/eg;
92
93 # Resolve the string arguments using sprintf, then write out to the handle
94 my $text_string_resolved = sprintf($text_string, @text_arguments);
95
96 if($multiline) { # replace newlines
97 $text_string_resolved =~ s@\\n@\n@g;
98 }
99
100 if ($freetext_xml_mode) {
101 $text_string_resolved = make_freetext_xml_safe($text_string_resolved);
102 }
103
104 print $handle $text_string_resolved;
105}
106
107
108
109sub lookup_string
110{
111 my ($stringkey, $native_perl) = @_;
112
113 if (!defined $native_perl || $native_perl != 1) {
114 $native_perl = 0;
115 }
116 return "" unless defined $stringkey;
117 # Try the language-specific resource bundle first
118 my $utf8string = $specialresourcebundle{$stringkey};
119 my $outputencoding = $specialoutputencoding;
120
121 # Try the default resource bundle next
122 if (!defined($utf8string)) {
123 # Load the default resource bundle if it is not already loaded
124 &load_default_resource_bundle() if (!%defaultresourcebundle);
125
126 $utf8string = $defaultresourcebundle{$stringkey};
127 $outputencoding = $defaultoutputencoding;
128 }
129
130 # Try the English resource bundle last
131 if (!defined($utf8string)) {
132 # Load the English resource bundle if it is not already loaded
133 &load_english_resource_bundle() if (!%englishresourcebundle);
134
135 $utf8string = $englishresourcebundle{$stringkey};
136 $outputencoding = $englishoutputencoding;
137 }
138
139 # No matching string was found, so just return the key
140 if (!defined($utf8string)) {
141 return $stringkey;
142 }
143 # we allow \n and \t as newlines and tabs.
144 $utf8string =~ s@([^\\])\\n@$1\n@g;
145 $utf8string =~ s@([^\\])\\t@$1\t@g;
146 $utf8string =~ s@\\\\@\\@g;
147
148 if ($native_perl ==1) {
149 # decode the utf8 string to perl internal format
150 return decode("utf8", $utf8string);
151 }
152
153 # Return the utf8 string if our output encoding is utf8
154 if (!defined($outputencoding) || $outputstringsinUTF8
155 || $outputencoding eq "utf8") {
156 return $utf8string;
157 }
158
159 # If an 8-bit output encoding has been defined, encode the string appropriately
160 my $encoded=unicode::unicode2singlebyte(&unicode::utf82unicode($utf8string), $outputencoding);
161
162 # If we successfully encoded it, return it
163 if ($encoded) { return $encoded }
164
165 # Otherwise, we can't convert to the requested encoding. return the utf8?
166 $specialoutputencoding='utf8';
167 return $utf8string;
168}
169
170
171sub load_language_specific_resource_bundle
172{
173 my $language = shift(@_);
174
175 # Read the specified resource bundle
176 my $resourcebundlename = "strings_" . $language . ".properties";
177
178 %specialresourcebundle
179 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
180 return if (!%specialresourcebundle);
181
182 # Read the output encoding to use from the resource bundle
183 if ($ENV{'GSDLOS'} =~ /windows/) {
184 $specialoutputencoding = $specialresourcebundle{"{OutputEncoding.windows}"};
185 }
186 else {
187 # see if there is an encoding set in the appropriate locale env var
188
189 foreach my $envvar ('LC_ALL', 'LANG') {
190 if (!exists $ENV{$envvar}) { next }
191 my $locale=$ENV{$envvar};
192 if ($locale !~ /^\w+\.(.+)$/) { next }
193 my $enc=lc($1);
194 $enc =~ s/-/_/g;
195 if ($enc eq 'utf_8') { $enc='utf8' } # normalise to this name
196 $specialoutputencoding = $enc;
197 return;
198 }
199 $specialoutputencoding = $specialresourcebundle{"{OutputEncoding.unix}"};
200 }
201}
202
203
204sub load_default_resource_bundle
205{
206 # Read the default resource bundle
207 my $resourcebundlename = "strings.properties";
208
209 %defaultresourcebundle
210 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
211 if (!%defaultresourcebundle) {
212 # $! will still have the error value for the last failed syscall
213
214 my $error_message = "$! $resourcebundlename\n";
215
216 if ($freetext_xml_mode) {
217 $error_message = make_freetext_xml_safe($error_message);
218 }
219
220 print STDERR $error_message;
221
222 # set something so we don't bother trying to load it again
223 $defaultresourcebundle{0}=undef;
224 return;
225 }
226
227 # Read the output encoding to use from the resource bundle
228 if ($ENV{'GSDLOS'} =~ /windows/) {
229 $defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.windows}"};
230 }
231 else {
232 $defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.unix}"};
233 }
234}
235
236
237sub load_english_resource_bundle
238{
239 # Ensure the English resource bundle hasn't already been loaded
240 if (%specialresourcebundle && $specialresourcebundle{"{Language.code}"} eq "en") {
241 %englishresourcebundle = %specialresourcebundle;
242 $englishoutputencoding = $specialoutputencoding;
243 }
244
245 if ($defaultresourcebundle{"{Language.code}"} &&
246 $defaultresourcebundle{"{Language.code}"} eq "en") {
247 %englishresourcebundle = %defaultresourcebundle;
248 $englishoutputencoding = $defaultoutputencoding;
249 }
250
251 # Read the English resource bundle
252 my $resourcebundlename = "strings_en.properties";
253
254 %englishresourcebundle
255 = &read_resource_bundle_and_extensions($ENV{'GSDLHOME'},"perllib",$resourcebundlename);
256 return if (!%englishresourcebundle);
257
258 # Read the output encoding to use from the resource bundle
259 if ($ENV{'GSDLOS'} =~ /windows/) {
260 $englishoutputencoding = $englishresourcebundle{"{OutputEncoding.windows}"};
261 }
262 else {
263 $englishoutputencoding = $englishresourcebundle{"{OutputEncoding.unix}"};
264 }
265}
266
267
268sub read_resource_bundle_and_extensions
269{
270 my ($bundle_base,$primary_dir,$resourcename) = @_;
271
272 my $primary_resourcebundlefile
273 = &FileUtils::filenameConcatenate($bundle_base,$primary_dir,$resourcename);
274
275 my $resourcebundle = read_resource_bundle($primary_resourcebundlefile);
276 return if (!defined $resourcebundle);
277
278 if (defined $ENV{'GSDLEXTS'}) {
279 my @extensions = split(/:/,$ENV{'GSDLEXTS'});
280 foreach my $e (@extensions) {
281 my $ext_base
282 = &FileUtils::filenameConcatenate($bundle_base,"ext",$e);
283
284 my $ext_resourcebundlefile
285 = &FileUtils::filenameConcatenate($ext_base,$primary_dir,$resourcename);
286
287 # can ignore return value (will be same reference to $resourcebundle)
288 read_resource_bundle($ext_resourcebundlefile,$resourcebundle);
289 }
290 }
291 if (defined $ENV{'GSDL3EXTS'}) {
292 my @extensions = split(/:/,$ENV{'GSDL3EXTS'});
293 foreach my $e (@extensions) {
294 my $ext_base
295 = &FileUtils::filenameConcatenate($ENV{'GSDL3SRCHOME'},"ext",$e);
296
297 my $ext_resourcebundlefile
298 = &FileUtils::filenameConcatenate($ext_base,$primary_dir,$resourcename);
299
300 # can ignore return value (will be same reference to $resourcebundle)
301 read_resource_bundle($ext_resourcebundlefile,$resourcebundle);
302 }
303 }
304
305 return %$resourcebundle;
306}
307
308
309sub read_resource_bundle
310{
311 my ($resourcebundlefilepath,$resourcebundle) = @_;
312
313 if (!open(RESOURCE_BUNDLE, "<$resourcebundlefilepath")) {
314 # When called for the first time (primary resource), $resourcebundle
315 # is not defined (=undef). If the file does not exist, then we return
316 # this 'undef' to signal it was not found
317 # For an extension resource bundle, if it does not exist this
318 # is not so serious (in fact quite likely) => return what we
319 # have built up so far
320
321 return $resourcebundle;
322 }
323
324 if (!defined $resourcebundle) {
325 # resource files exists, so exect some content to be stored
326 $resourcebundle = {};
327 }
328
329 # Load this resource bundle
330 my @resourcebundlelines = <RESOURCE_BUNDLE>;
331 close(RESOURCE_BUNDLE);
332
333 # Parse the resource bundle
334
335 foreach my $line (@resourcebundlelines) {
336 # Remove any trailing whitespace
337 $line =~ s/(\s*)$//;
338
339 # Ignore comments and empty lines
340 if ($line !~ /^\#/ && $line ne "") {
341 # Parse key (everything up to the first colon)
342 if ($line =~ m/^([^:]+):(.+)$/) {
343 my $linekey = "{" . $1 . "}";
344 my $linetext = $2;
345 $linetext =~ s/(\s*)\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d).*$//i;
346
347 # Map key to text
348 $resourcebundle->{$linekey} = $linetext;
349 }
350 }
351 }
352
353 return $resourcebundle;
354}
355
356
357sub set_print_freetext_for_xml
358{
359 $freetext_xml_mode = 1;
360}
361
362sub set_print_xml_tags
363{
364 $freetext_xml_mode = 0;
365}
366
367sub output_strings_in_UTF8
368{
369 $outputstringsinUTF8 = 1;
370}
371
372
373sub debug_unicode_string
374{
375 join("",
376 map { $_ > 255 ? # if wide character...
377 sprintf("\\x{%04X}", $_) : # \x{...}
378 chr($_)
379 } unpack("U*", $_[0])); # unpack Unicode characters
380}
381
382
3831;
Note: See TracBrowser for help on using the repository browser.