File Coverage

blib/lib/Locale/gettext_dumb.pm
Criterion Covered Total %
statement 21 41 51.2
branch 8 8 100.0
condition 8 12 66.6
subroutine 6 16 37.5
pod 0 13 0.0
total 43 90 47.7


line stmt bran cond sub pod time code
1             #! /bin/false
2              
3             # vim: set autoindent shiftwidth=4 tabstop=4:
4              
5             # Pure Perl implementation of Uniforum message translation.
6             # Copyright (C) 2002-2026 Guido Flohr <guido.flohr@cantanea.com>,
7             # all rights reserved.
8              
9             # This program is free software: you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by
11             # the Free Software Foundation; either version 3 of the License, or
12             # (at your option) any later version.
13              
14             # This program is distributed in the hope that it will be useful,
15             # but WITHOUT ANY WARRANTY; without even the implied warranty of
16             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17             # GNU General Public License for more details.
18              
19             # You should have received a copy of the GNU General Public License
20             # along with this program. If not, see <http://www.gnu.org/licenses/>.
21              
22             package Locale::gettext_dumb;
23              
24 1     1   9 use Locale::gettext_pp;
  1         2  
  1         72  
25              
26 1     1   6 use vars qw (%EXPORT_TAGS @EXPORT_OK @ISA $VERSION);
  1         3  
  1         1567  
27              
28             %EXPORT_TAGS = (locale_h => [ qw (gettext
29             dgettext
30             dcgettext
31             ngettext
32             dngettext
33             dcngettext
34             pgettext
35             dpgettext
36             dcpgettext
37             npgettext
38             dnpgettext
39             dcnpgettext
40             textdomain
41             bindtextdomain
42             bind_textdomain_codeset
43             )],
44             libintl_h => [ qw (LC_CTYPE
45             LC_NUMERIC
46             LC_TIME
47             LC_COLLATE
48             LC_MONETARY
49             LC_MESSAGES
50             LC_ALL)],
51             );
52              
53             @EXPORT_OK = qw (gettext
54             dgettext
55             dcgettext
56             ngettext
57             dngettext
58             dcngettext
59             pgettext
60             dpgettext
61             dcpgettext
62             npgettext
63             dnpgettext
64             dcnpgettext
65             textdomain
66             bindtextdomain
67             bind_textdomain_codeset
68             nl_putenv
69             setlocale
70             LC_CTYPE
71             LC_NUMERIC
72             LC_TIME
73             LC_COLLATE
74             LC_MONETARY
75             LC_MESSAGES
76             LC_ALL);
77            
78             @ISA = qw (Exporter);
79              
80             *Locale::gettext_dumb::textdomain = \&Locale::gettext_pp::textdomain;
81             *Locale::gettext_dumb::bindtextdomain = \&Locale::gettext_pp::bindtextdomain;
82             *Locale::gettext_dumb::bind_textdomain_codeset =
83             \&Locale::gettext_pp::bind_textdomain_codeset;
84              
85             *Locale::gettext_dumb::nl_putenv = \&Locale::gettext_pp::nl_putenv;
86              
87             *Locale::gettext_dumb::LC_CTYPE = \&Locale::gettext_pp::LC_CTYPE;
88             *Locale::gettext_dumb::LC_NUMERIC = \&Locale::gettext_pp::LC_NUMERIC;
89             *Locale::gettext_dumb::LC_TIME= \&Locale::gettext_pp::LC_TIME;
90             *Locale::gettext_dumb::LC_COLLATE = \&Locale::gettext_pp::LC_COLLATE;
91             *Locale::gettext_dumb::LC_MONETARY = \&Locale::gettext_pp::LC_MONETARY;
92             *Locale::gettext_dumb::LC_MESSAGES = \&Locale::gettext_pp::LC_MESSAGES;
93             *Locale::gettext_dumb::LC_ALL = \&Locale::gettext_pp::LC_ALL;
94              
95              
96             sub gettext ($) {
97 9     9 0 11 my ($msgid) = @_;
98              
99 9         21 return dcnpgettext ('', undef, $msgid, undef, undef, undef);
100             }
101              
102             sub dgettext ($$) {
103 0     0 0 0 my ($domainname, $msgid) = @_;
104              
105 0         0 return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
106             }
107              
108             sub dcgettext ($$$) {
109 0     0 0 0 my ($domainname, $msgid, $category) = @_;
110              
111 0         0 return dcnpgettext ($domainname, undef, $msgid, undef, undef, undef);
112             }
113              
114             sub ngettext ($$$) {
115 0     0 0 0 my ($msgid, $msgid_plural, $n) = @_;
116              
117 0         0 return dcnpgettext ('', undef, $msgid, $msgid_plural, $n, undef);
118             }
119              
120             sub dngettext ($$$$) {
121 0     0 0 0 my ($domainname, $msgid, $msgid_plural, $n) = @_;
122              
123 0         0 return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, undef);
124             }
125              
126             sub dcngettext ($$$$$) {
127 0     0 0 0 my ($domainname, $msgid, $msgid_plural, $n, $category) = @_;
128              
129 0         0 return dcnpgettext ($domainname, undef, $msgid, $msgid_plural, $n, ,
130             $category);
131             }
132              
133             sub pgettext ($$) {
134 0     0 0 0 my ($msgctxt, $msgid) = @_;
135              
136 0         0 return dcnpgettext ('', $msgctxt, $msgid, undef, undef, undef);
137             }
138              
139             sub dpgettext ($$$) {
140 0     0 0 0 my ($domainname, $msgctxt, $msgid) = @_;
141              
142 0         0 return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
143             }
144              
145             sub dcpgettext($$$$) {
146 0     0 0 0 my ($domainname, $msgctxt, $msgid, $category) = @_;
147              
148 0         0 return dcnpgettext ($domainname, $msgctxt, $msgid, undef, undef, undef);
149             }
150              
151             sub npgettext ($$$$) {
152 0     0 0 0 my ($msgctxt, $msgid, $msgid_plural, $n) = @_;
153              
154 0         0 return dcnpgettext ('', $msgctxt, $msgid, $msgid_plural, $n, undef);
155             }
156              
157             sub dnpgettext ($$$$$) {
158 0     0 0 0 my ($domainname, $msgctxt, $msgid, $msgid_plural, $n) = @_;
159              
160 0         0 return dcnpgettext ($domainname, $msgctxt, $msgid, $msgid_plural, $n, undef);
161             }
162              
163             sub __get_locale() {
164 9     9   11 my $locale;
165              
166 9 100 66     58 if (exists $ENV{LANGUAGE} && length $ENV{LANGUAGE}) {
    100 66        
    100 66        
    100 66        
167 2         3 $locale = $ENV{LANGUAGE};
168 2         16 $locale =~ s/:.*//s;
169             } elsif (exists $ENV{LC_ALL} && length $ENV{LC_ALL}) {
170 2         3 $locale = $ENV{LC_ALL};
171             } elsif (exists $ENV{LANG} && length $ENV{LANG}) {
172 2         3 $locale = $ENV{LANG};
173             } elsif (exists $ENV{LC_MESSAGES} && length $ENV{LC_MESSAGES}) {
174 2         4 $locale = $ENV{LC_MESSAGES};
175             } else {
176 1         2 $locale = 'C';
177             }
178            
179 9         11 return $locale;
180             }
181              
182             sub dcnpgettext ($$$$$$) {
183 9     9 0 17 my ($domainname, $msgctxt, $msgid, $msgid_plural, $n, $category) = @_;
184              
185 9         13 my $locale = __get_locale;
186              
187 9         25 return Locale::gettext_pp::_dcnpgettext_impl ($domainname, $msgctxt,
188             $msgid, $msgid_plural, $n,
189             $category, $locale);
190             }
191              
192             sub setlocale($;$) {
193 1     1 0 17 &POSIX::setlocale;
194             }
195              
196             1;
197              
198             __END__
199              
200             =head1 NAME
201              
202             Locale::gettext_dumb - Locale unaware Implementation of Uniforum Message Translation
203              
204             =head1 SYNOPSIS
205              
206             use Locale::gettext_dumb qw(:locale_h :libintl_h);
207              
208             # Normally, you will not want to include this module directly but this way:
209             use Locale::Messages;
210            
211             my $selected = Locale::Messages->select_package ('gettext_dumb');
212              
213             gettext $msgid;
214             dgettext $domainname, $msgid;
215             dcgettext $domainname, $msgid, LC_MESSAGES;
216             ngettext $msgid, $msgid_plural, $count;
217             dngettext $domainname, $msgid, $msgid_plural, $count;
218             dcngettext $domainname, $msgid, $msgid_plural, $count, LC_MESSAGES;
219             pgettext $msgctxt, $msgid;
220             dpgettext $domainname, $msgctxt, $msgid;
221             dcpgettext $domainname, $msgctxt, $msgid, LC_MESSAGES;
222             npgettext $msgctxt, $msgid, $msgid_plural, $count;
223             dnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count;
224             dcnpgettext $domainname, $msgctxt, $msgid, $msgid_plural, $count, LC_MESSAGES;
225             textdomain $domainname;
226             bindtextdomain $domainname, $directory;
227             bind_textdomain_codeset $domainname, $encoding;
228             my $category = LC_CTYPE;
229             my $category = LC_NUMERIC;
230             my $category = LC_TIME;
231             my $category = LC_COLLATE;
232             my $category = LC_MONETARY;
233             my $category = LC_MESSAGES;
234             my $category = LC_ALL;
235              
236             =head1 DESCRIPTION
237              
238             B<IMPORTANT!> This module is experimental. It may not work as described!
239              
240             The module B<Locale::gettext_dumb> does exactly the same as
241             Locale::gettext_xs(3pm) or Locale::gettext_pp(3pm).
242              
243             While both other modules use POSIX::setlocale() to determine the currently
244             selected locale, this backend only checks the environment variables
245             LANGUAGE, LANG, LC_ALL, LC_MESSAGES (in that order), when it tries to locate
246             a message catalog (a .mo file).
247              
248             This class was introduced in libintl-perl 1.22.
249              
250             =head1 USAGE
251              
252             This module should not be used for desktop software or scripts run locally.
253             Why? If you use a message catalog for example in Danish in UTF-8 (da_DA.UTF8)
254             but the system locale is set to Russian with KOI8-R (ru_RU.KOI8-R) you
255             may produce invalid output, either invalid multi-byte sequences or invalid
256             text, depending on how you look at it.
257              
258             That will happen, when you mix output from B<Locale::gettext_pp> with
259             locale-dependent output from the operating system like the contents of
260             the variable "$!", date and time formatting functions (localtime(),
261             gmtime(), POSIX::strftime() etc.), number formatting with printf() and
262             friends, and so on.
263              
264             A typical usage scenario looks like this:
265              
266             You have a server application (for example a web application) that is supposed
267             to display a fixed set of messages in many languages. If you want to do this
268             with Locale::gettext_xs(3pm) or Locale::gettext_pp(3pm), you have to install
269             the locale data for all of those languages. Otherwise, translating the
270             messages will not work.
271              
272             With Locale::gettext_dumb(3pm) you can relax these requirements, and display
273             messages for all languages that you have mo files for.
274              
275             On the other hand, you will soon reach limits with this approach. Almost
276             any application requires more than bare translation of messages for
277             localisation. You want to formatted dates and times, you want to display
278             numbers in the correct formatting for the selected languages, and you may
279             want to display system error messages ("$!").
280              
281             In practice, Locale::gettext_dumb(3pm) is still useful in these scenarios.
282             Your users will have to live with the fact that the presented output is
283             in different languages resp. for different locales, when "their" locale
284             is not installed on your system.
285              
286             More dangerous is mixing output in different character sets but that can
287             be easily avoided. Simply make sure that B<Locale::gettext_dump> uses
288             UTF-8 (for example by setting the environment variable OUTPUT_CHARSET or
289             by calling bind_textdomain_codeset()) and make sure that the system locale
290             also uses UTF-8, for example "en_US.UTF8". If that fails, switch to a
291             locale that uses a subset of UTF-8. In practice that will be US-ASCII, the
292             character set used by the default locale "C" resp. "POSIX".
293              
294             Your application will then to a certain extent mix output for different
295             localisations resp. languages. But this is completely under your control.
296              
297             =head1 EXAMPLE
298              
299             See above! Normally you should not use this module! However, let us assume
300             you have read the warnings. In a web application you would do something
301             like this:
302              
303             use Locale::TextDomain qw (com.example.yourapp);
304             use Locale::Messages qw (nl_putenv LC_ALL bindtextdomain
305             bind_textdomain_codeset);
306             use Locale::Util qw (web_set_locale);
307             use POSIX qw (setlocale);
308            
309             # First try to switch to the locale requested by the user. If you
310             # know it you can try to pass it to setlocale like this:
311             #
312             # my $hardcoded_locale = 'fr_FR.UTF-8';
313             # my $success = POSIX::setlocale (LC_ALL, $hardcoded_locale);
314             #
315             # However, we try to let libintl-perl do a better job for us:
316             my $success = web_set_locale $ENV{HTTP_ACCEPT_LANGUAGE},
317             $ENV{HTTP_ACCEPT_CHARSET};
318             # Note: If your application forces the use of UTF-8 for its output
319             # you should pass 'UTF-8' as the second argument to web_set_locale
320             # instead of $ENV{HTTP_ACCEPT_CHARSET}.
321            
322             if (!$success) {
323             # Did not work. Switch to the dumb interface of
324             # Locale::Messages.
325             Locale::Messages->select_package ('gettext_dumb');
326            
327             # And try to switch to a default locale:
328             if (!setlocale (LC_ALL, 'en_US.UTF-8')) {
329             # Still no luck. Enforce at least US-ASCII:
330             setlocale (LC_ALL, 'C');
331             }
332             bind_textdomain_codeset 'com.example.yourapp', 'utf-8';
333             }
334            
335             If your application forces the usage of UTF-8 you should ignore the environment
336             variable
337            
338             =head1 AUTHOR
339              
340             Copyright (C) 2002-2026 L<Guido Flohr|http://www.guido-flohr.net/>
341             (L<mailto:guido.flohr@cantanea.com>), all rights reserved. See the source
342             code for details!code for details!
343              
344             =head1 SEE ALSO
345              
346             Locale::TextDomain(3pm), Locale::Messages(3pm), Encode(3pm),
347             perllocale(3pm), POSIX(3pm), perl(1), gettext(1), gettext(3)
348              
349             =cut
350              
351             Local Variables:
352             mode: perl
353             perl-indent-level: 4
354             perl-continued-statement-offset: 4
355             perl-continued-brace-offset: 0
356             perl-brace-offset: -4
357             perl-brace-imaginary-offset: 0
358             perl-label-offset: -4
359             tab-width: 4
360             End: