722974393f8801537b236bcd12ae35b35fda2bbf
[kivitendo-erp.git] / SL / Locale / String.pm
1 package SL::Locale::String;
2
3 use strict;
4
5 use parent qw(Rose::Object Exporter);
6
7 use Rose::Object::MakeMethods::Generic (
8   scalar => [ qw(untranslated) ],
9   array  => [ qw(args) ],
10 );
11
12 our @EXPORT = qw(t8);
13
14 use overload
15   '""' => \&translated,
16   eq   => \&my_eq,
17   ne   => \&my_ne;
18
19 sub translated {
20   my ($self) = @_;
21   return $::locale ? $::locale->text($self->untranslated, $self->args) : $self->untranslated;
22 }
23
24 sub t8 {
25   shift if $_[0] eq __PACKAGE__;
26
27   my $string = shift;
28   return SL::Locale::String->new(untranslated => $string, args => [ @_ ]);
29 }
30
31 sub my_eq {
32   $_[1] eq $_[0]->translated;
33 }
34
35 sub my_ne {
36   $_[1] ne $_[0]->translated;
37 }
38
39 sub TO_JSON {
40   return $_[0]->translated;
41 }
42
43 1;
44 __END__
45
46 =pod
47
48 =encoding utf8
49
50 =head1 NAME
51
52 SL::Locale::String - Helper class for translating strings at a later
53 date (e.g. use at compile time, actual translation during execution
54 time)
55
56 =head1 SYNOPSIS
57
58   use SL::Locale::String;
59
60   use SL::Controller::Helper::Sorted;
61
62   __PACKAGE__->make_sorted(
63     ...
64     qty => { title => t8("Quantity") },
65  );
66
67 =head1 OVERVIEW
68
69 Every string that should be translated must be recognized by our
70 translation helper script C<script/locales.pl> somehow. It recognizes
71 certain function calls as translation instructions and extracts its
72 arguments for translation by developers/translators.
73
74 This works well for calls that occur during execution time: C<<
75 $::locale->text("Untranslated") >>. However, for untranslated strings
76 that need to be used at compile time this fails in subtle and not so
77 subtle ways. If it happens in a module that is C<use>d directly from
78 the dispatcher then C<$::locale> is not defined and such a call would
79 end in an error. For modules like controllers that are C<require>d
80 during execution time it seems to work, but in FastCGI situations this
81 means that the first call determines the language and all subsequent
82 calls end up using the same language no matter which language the user
83 has chosen.
84
85 This class solves the issue by providing a small function called L<t8>
86 which can be used instead of C<< $::locale->text() >>. It is
87 recognized by C<script/locales.pl>. The untranslated string given to
88 L<t8> is stored in an instance of C<SL::Locale::String> and translated
89 only when requested either by calling L<translated> or by
90 stringification.
91
92 Instances of this class can safely be handed over to C<<
93 $::locale->text() >> which knows how to handle them (and not to
94 re-translate them).
95
96 The function L<t8> is exported by default.
97
98 =head1 FUNCTIONS
99
100 =head2 EXPORTED FUNCTIONS
101
102 =over 4
103
104 =item C<t8 $untranslated_string>
105
106 Returns a new instance of C<SL::Locale::String> and sets its
107 L<untranslated> member to C<$untranslated_string>. This function is
108 exported and cannot be called as a class or instance method.
109
110 =back
111
112 =head2 INSTANCE FUNCTIONS
113
114 =over 4
115
116 =item C<untranslated [$new_untranslated]>
117
118 Gets or sets the untranslated string.
119
120 =item C<translated>
121
122 Returns the translated version of the untranslated string. Translation
123 occurs when this function is called and not when the object instance
124 is created.
125
126 This function is also called during stringification.
127
128 =back
129
130 =head1 BUGS
131
132 Nothing here yet.
133
134 =head1 AUTHOR
135
136 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
137
138 =cut