File Coverage

blib/lib/Lingua/String.pm
Criterion Covered Total %
statement 86 89 96.6
branch 41 46 89.1
condition 10 18 55.5
subroutine 11 12 91.6
pod 4 4 100.0
total 152 169 89.9


line stmt bran cond sub pod time code
1             package Lingua::String;
2              
3 4     4   415669 use strict;
  4         35  
  4         107  
4 4     4   17 use warnings;
  4         7  
  4         88  
5 4     4   17 use Carp;
  4         6  
  4         181  
6 4     4   1756 use HTML::Entities;
  4         19876  
  4         455  
7              
8             =head1 NAME
9              
10             Lingua::String - Class to contain a string in many different languages
11              
12             =head1 VERSION
13              
14             Version 0.03
15              
16             =cut
17              
18             our $VERSION = '0.03';
19              
20             use overload (
21             # '==' => \&equal,
22             # '!=' => \¬_equal,
23             '""' => \&as_string,
24 0     0   0 bool => sub { 1 },
25 4         51 fallback => 1 # So that boolean tests don't cause as_string to be called
26 4     4   31 );
  4         6  
27              
28             =head1 SYNOPSIS
29              
30             Hold many strings in one object.
31              
32             use Lingua::String;
33              
34             my $str = Lingua::String->new();
35              
36             $str->fr('Bonjour Tout le Monde');
37             $str->en('Hello, World');
38              
39             $ENV{'LANG'} = 'en_GB';
40             print "$str\n"; # Prints Hello, World
41             $ENV{'LANG'} = 'fr_FR';
42             print "$str\n"; # Prints Bonjour Tout le Monde
43             $LANG{'LANG'} = 'de_DE';
44             print "$str\n"; # Prints nothing
45              
46             $string = Lingua::String->new('hello'); # Initialises the 'current' language
47              
48             =cut
49              
50             =head1 METHODS
51              
52             =head2 new
53              
54             Create a Lingua::String object.
55              
56             use Lingua::String;
57              
58             my $str = Lingua::String->new({ 'en' => 'Here', 'fr' => 'Ici' });
59              
60             =cut
61              
62             sub new {
63 10     10 1 554 my $proto = shift;
64 10   66     41 my $class = ref($proto) || $proto;
65              
66             # Use Lingua::String->new, not Lingua::String::new
67 10 100       24 if(!defined($class)) {
68             # Using Lingua::String->new(), not Lingua::String::new()
69             # carp(__PACKAGE__, ' use ->new() not ::new() to instantiate');
70             # return;
71 1         2 $class = __PACKAGE__;
72             }
73              
74 10         13 my %params;
75 10 100 66     54 if(ref($_[0]) eq 'HASH') {
    100          
    100          
76 1         2 %params = %{$_[0]};
  1         4  
77             } elsif((scalar(@_) == 1) && (my $lang = _get_language())) {
78 1         3 %params = ($lang => $_[0]);
79             } elsif(scalar(@_) % 2 == 0) {
80 7         18 %params = @_;
81             } else {
82 1         2 Carp::carp(__PACKAGE__, ': usage: new(%args)');
83 1         269 return;
84             }
85              
86 9 100       19 if(scalar(%params)) {
87 5         19 return bless { strings => \%params }, $class;
88             }
89 4         18 return bless { }, $class;
90             }
91              
92             =head2 set
93              
94             Sets a string in a language.
95              
96             $str->set({ string => 'House', lang => 'en' });
97              
98             Autoload will do this for you as
99              
100             $str->en('House');
101              
102             =cut
103              
104             sub set {
105 5     5 1 585 my $self = shift;
106              
107 5         8 my %params;
108 5 100       25 if(ref($_[0]) eq 'HASH') {
    100          
109 1         2 %params = %{$_[0]};
  1         5  
110             } elsif(scalar(@_) % 2 == 0) {
111 3         8 %params = @_;
112             } else {
113 1         2 $params{'string'} = shift;
114             }
115              
116 5         9 my $lang = $params{'lang'};
117              
118 5 100       13 if(!defined($lang)) {
119 2   66     10 $lang ||= $self->_get_language();
120 2 100       7 if(!defined($lang)) {
121 1         3 Carp::carp(__PACKAGE__, ': usage: set(string => string, lang => $language)');
122 1         284 return;
123             }
124             }
125              
126 4         8 my $string = $params{'string'};
127              
128 4 100       9 if(!defined($string)) {
129 1         3 Carp::carp(__PACKAGE__, ': usage: set(string => string, lang => $language)');
130 1         249 return;
131             }
132              
133 3         6 $self->{'strings'}->{$lang} = $string;
134              
135 3         12 return $self;
136             }
137              
138             # https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html
139             # https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html
140             sub _get_language {
141 18 100   18   41 if($ENV{'LANGUAGE'}) {
142 1 50       12 if($ENV{'LANGUAGE'} =~ /^([a-z]{2})/i) {
143 0         0 return lc($1);
144             }
145             }
146 18         34 foreach my $variable('LC_ALL', 'LC_MESSAGES', 'LANG') {
147 38         55 my $val = $ENV{$variable};
148 38 100       66 next unless(defined($val));
149              
150 16 50       57 if($val =~ /^([a-z]{2})/i) {
151 16         64 return lc($1);
152             }
153             }
154 2 0 0     5 if(defined($ENV{'LANG'}) && (($ENV{'LANG'} =~ /^C\./) || ($ENV{'LANG'} eq 'C'))) {
      33        
155 0         0 return 'en';
156             }
157 2         16 return; # undef
158             }
159              
160             =head2 as_string
161              
162             Returns the string in the language requested in the parameter.
163             If that parameter is not given, the system language is used.
164              
165             my $string = Lingua::String->new(en => 'boat', fr => 'bateau');
166             print $string->as_string(), "\n";
167             print $string->as_string('fr'), "\n";
168             print $string->as_string({ lang => 'en' }), "\n";
169              
170             =cut
171              
172             sub as_string {
173 19     19 1 1059 my $self = shift;
174 19         36 my %params;
175              
176 19 100       66 if(ref($_[0]) eq 'HASH') {
    100          
    100          
177 2         3 %params = %{$_[0]};
  2         7  
178             } elsif(scalar(@_) == 0) {
179             # $params{'lang'} = $self->_get_language();
180             } elsif(scalar(@_) % 2 == 0) {
181 7 100       16 if(defined($_[0])) {
182 1         4 %params = @_;
183             }
184             } else {
185 1         2 $params{'lang'} = shift;
186             }
187 19   100     77 my $lang = $params{'lang'} || $self->_get_language();
188              
189 19 100       40 if(!defined($lang)) {
190 1         4 Carp::carp(__PACKAGE__, ': usage: as_string(lang => $language)');
191 1         260 return;
192             }
193 18         104 return $self->{'strings'}->{$lang};
194             }
195              
196             =head2 encode
197              
198             =encoding utf-8
199              
200             Turns the encapsulated strings into HTML entities
201              
202             my $string = Lingua::String->new(en => 'study', fr => 'étude')->encode();
203             print $string->fr(), "\n"; # Prints étude
204              
205             =cut
206              
207             sub encode {
208 2     2 1 570 my $self = shift;
209              
210 2         4 while(my($k, $v) = each(%{$self->{'strings'}})) {
  6         114  
211 4         12 utf8::decode($v);
212 4         9 $self->{'strings'}->{$k} = HTML::Entities::encode_entities($v);
213             }
214 2         11 return $self;
215             }
216              
217             sub AUTOLOAD {
218 16     16   1973 our $AUTOLOAD;
219 16         22 my $key = $AUTOLOAD;
220              
221 16         69 $key =~ s/.*:://;
222              
223 16 100       252 return if($key eq 'DESTROY');
224              
225 7         12 my $self = shift;
226              
227 7 50       14 return if(ref($self) ne __PACKAGE__);
228              
229 7 100       14 if(my $value = shift) {
230 2         24 $self->{'strings'}->{$key} = $value;
231             }
232              
233 7         31 return $self->{'strings'}->{$key};
234             }
235              
236             =head1 AUTHOR
237              
238             Nigel Horne, C<< >>
239              
240             =head1 BUGS
241              
242             There's no decode() (yet) so you'll have to be extra careful to avoid
243             double encoding.
244              
245             =head1 SEE ALSO
246              
247             =head1 SUPPORT
248              
249             You can find documentation for this module with the perldoc command.
250              
251             perldoc Lingua::String
252              
253             You can also look for information at:
254              
255             =over 4
256              
257             =item * MetaCPAN
258              
259             L
260              
261             =item * RT: CPAN's request tracker
262              
263             L
264              
265             =item * CPANTS
266              
267             L
268              
269             =item * CPAN Testers' Matrix
270              
271             L
272              
273             =item * CPAN Testers Dependencies
274              
275             L
276              
277             =back
278              
279             =head1 LICENCE AND COPYRIGHT
280              
281             Copyright 2021-2022 Nigel Horne.
282              
283             This program is released under the following licence: GPL2 for personal use on
284             a single computer.
285             All other users (for example Commercial, Charity, Educational, Government)
286             must apply in writing for a licence for use from Nigel Horne at ``.
287              
288             =cut
289              
290             1;