1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """internationalization helpers
23 """
24
25 import os
26 import gettext
27
28 from twisted.spread import pb
29
30 from flumotion.common import log
31 from flumotion.configure import configure
32
33 __version__ = "$Rev: 6693 $"
34
35
36
37
38
39
40
42 compareAttributes = ()
43
45 if not self.compareAttributes:
46 return self is other
47
48 if not isinstance(other, self.__class__):
49 return False
50 for attr in self.compareAttributes:
51 if hasattr(self, attr):
52 if not hasattr(other, attr):
53 return False
54 elif not getattr(self, attr) == getattr(other, attr):
55 return False
56 elif hasattr(other, attr):
57 return False
58 return True
59
61 return not self.__eq__(other)
62
63
65 """
66 Mark a singular string for translation, without translating it.
67 """
68 return format
69
70
71 -def ngettext(singular, plural, count):
72 """
73 Mark a plural string for translation, without translating it.
74 """
75 return (singular, plural, count)
76
77
79 """
80 Return a function that takes a format string or tuple, and additional
81 format args,
82 and creates a L{Translatable} from it.
83
84 Example::
85
86 T_ = gettexter('flumotion')
87 t = T_(N_("Could not find '%s'."), file)
88
89 @param domain: the gettext domain to create translatables for.
90 """
91
92 def create(format, *args):
93 if isinstance(format, str):
94 return TranslatableSingular(domain, format, *args)
95 else:
96 return TranslatablePlural(domain, format, *args)
97
98 return lambda *args: create(*args)
99
100
102 """
103 I represent a serializable translatable gettext msg.
104 """
105 domain = None
106
107
108
109
110
111
112
113
114
115
117 """
118 I represent a translatable gettext msg in the singular form.
119 """
120
121 compareAttributes = ["domain", "format", "args"]
122
123 - def __init__(self, domain, format, *args):
124 """
125 @param domain: the text domain for translations of this message
126 @param format: a format string
127 @param args: any arguments to the format string
128 """
129 self.domain = domain
130 self.format = format
131 self.args = args
132
134 if self.args:
135 result = self.format % self.args
136 else:
137 result = self.format
138 return result
139 pb.setUnjellyableForClass(TranslatableSingular, TranslatableSingular)
140
141
143 """
144 I represent a translatable gettext msg in the plural form.
145 """
146
147 compareAttributes = ["domain", "singular", "plural", "count", "args"]
148
149 - def __init__(self, domain, format, *args):
150 """
151 @param domain: the text domain for translations of this message
152 @param format: a (singular, plural, count) tuple
153 @param args: any arguments to the format string
154 """
155 singular, plural, count = format
156 self.domain = domain
157 self.singular = singular
158 self.plural = plural
159 self.count = count
160 self.args = args
161
163 if self.args:
164 result = self.singular % self.args
165 else:
166 result = self.singular
167 return result
168 pb.setUnjellyableForClass(TranslatablePlural, TranslatablePlural)
169
170
172 """
173 I translate translatables and messages.
174 I need to be told where locale directories can be found for all domains
175 I need to translate for.
176 """
177
178 logCategory = "translator"
179
181 self._localedirs = {}
182
184 """
185 Add a locale directory for the given text domain.
186 """
187 if not domain in self._localedirs.keys():
188 self._localedirs[domain] = []
189
190 if not dir in self._localedirs[domain]:
191 self.debug('Adding localedir %s for domain %s' % (dir, domain))
192 self._localedirs[domain].append(dir)
193
195 """
196 Translate a translatable object, in the given language.
197
198 @param lang: language code (or the current locale if None)
199 """
200
201 domain = translatable.domain
202 t = None
203 if domain in self._localedirs.keys():
204
205 for localedir in self._localedirs[domain]:
206 try:
207 t = gettext.translation(domain, localedir, lang)
208 except IOError:
209 pass
210 else:
211 self.debug('no locales for domain %s' % domain)
212
213 format = None
214 if not t:
215
216 self.debug('no translation found, falling back to C')
217 if isinstance(translatable, TranslatableSingular):
218 format = translatable.format
219 elif isinstance(translatable, TranslatablePlural):
220 if translatable.count == 1:
221 format = translatable.singular
222 else:
223 format = translatable.plural
224 else:
225 raise NotImplementedError('Cannot translate translatable %r' %
226 translatable)
227 else:
228
229 if isinstance(translatable, TranslatableSingular):
230 format = t.gettext(translatable.format)
231 elif isinstance(translatable, TranslatablePlural):
232 format = t.ngettext(translatable.singular, translatable.plural,
233 translatable.count)
234 else:
235 raise NotImplementedError('Cannot translate translatable %r' %
236 translatable)
237
238 if translatable.args:
239 return format % translatable.args
240 else:
241 return format
242
244 """
245 Translate a message, in the given language.
246 """
247 strings = []
248 for t in message.translatables:
249 strings.append(self.translateTranslatable(t, lang))
250 return "".join(strings)
251
252
254 """
255 Return the (at most) two-letter language code set for message translation.
256 """
257
258
259 language = os.environ.get('LANGUAGE', None)
260 if language != None:
261 LL = language[:2]
262 else:
263 lang = os.environ.get('LANG', 'en')
264 LL = lang[:2]
265
266 return LL
267
268
270 """
271 Sets up gettext so that the program gets translated.
272 Use this in any Flumotion end-user application that needs translations.
273 """
274 import locale
275
276 localedir = os.path.join(configure.localedatadir, 'locale')
277 log.debug("locale", "Loading locales from %s" % localedir)
278 gettext.bindtextdomain(configure.PACKAGE, localedir)
279 gettext.textdomain(configure.PACKAGE)
280
281
282
283
284 if hasattr(locale, 'bindtextdomain'):
285 locale.bindtextdomain(configure.PACKAGE, localedir)
286 if hasattr(locale, 'textdomain'):
287 locale.textdomain(configure.PACKAGE)
288