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