comparison libs/AceLocale-2.0/AceLocale-2.0.lua @ 1:c11ca1d8ed91

Version 0.1
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:03:57 +0000
parents
children
comparison
equal deleted inserted replaced
0:4e2ce2894c21 1:c11ca1d8ed91
1 --[[
2 Name: AceLocale-2.0
3 Revision: $Rev: 18753 $
4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
5 Inspired By: Ace 1.x by Turan (turan@gryphon.com)
6 Website: http://www.wowace.com/
7 Documentation: http://www.wowace.com/index.php/AceLocale-2.0
8 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.0
9 Description: Localization library for addons to use to handle proper
10 localization and internationalization.
11 Dependencies: AceLibrary
12 ]]
13
14 local MAJOR_VERSION = "AceLocale-2.0"
15 local MINOR_VERSION = "$Revision: 18753 $"
16
17 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
18 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
19
20 local AceLocale = {}
21
22 local DEFAULT_LOCALE = "enUS"
23 local _G = getfenv(0)
24
25 local __baseTranslations__, __debugging__, __translations__, __baseLocale__, __translationTables__, __reverseTranslations__, __strictness__
26
27 local __call = function(self, key1, key2)
28 if key2 then
29 return self[key1][key2]
30 else
31 return self[key1]
32 end
33 end
34
35 local rawget = rawget
36 local rawset = rawset
37 local type = type
38
39 local lastSelf
40
41 local __index = function(self, key)
42 lastSelf = self
43 local value = (rawget(self, __translations__) or AceLocale.prototype)[key]
44 rawset(self, key, value)
45 return value
46 end
47
48 local __newindex = function(self, k, v)
49 if type(v) ~= "function" and type(k) ~= "table" then
50 AceLocale.error(self, "Cannot change the values of an AceLocale instance.")
51 end
52 rawset(self, k, v)
53 end
54
55 local __tostring = function(self)
56 if type(rawget(self, 'GetLibraryVersion')) == "function" then
57 return self:GetLibraryVersion()
58 else
59 return "AceLocale(" .. self[__name__] .. ")"
60 end
61 end
62
63 local refixInstance = function(instance)
64 if getmetatable(instance) then
65 setmetatable(instance, nil)
66 end
67 local translations = instance[__translations__]
68 if translations then
69 if getmetatable(translations) then
70 setmetatable(translations, nil)
71 end
72 local baseTranslations = instance[__baseTranslations__]
73 if getmetatable(baseTranslations) then
74 setmetatable(baseTranslations, nil)
75 end
76 if translations == baseTranslations or instance[__strictness__] then
77 setmetatable(instance, {
78 __index = __index,
79 __newindex = __newindex,
80 __call = __call,
81 __tostring = __tostring
82 })
83
84 setmetatable(translations, {
85 __index = AceLocale.prototype
86 })
87 else
88 setmetatable(instance, {
89 __index = __index,
90 __newindex = __newindex,
91 __call = __call,
92 __tostring = __tostring
93 })
94
95 setmetatable(translations, {
96 __index = baseTranslations,
97 })
98
99 setmetatable(baseTranslations, {
100 __index = AceLocale.prototype,
101 })
102 end
103 else
104 setmetatable(instance, {
105 __index = __index,
106 __newindex = __newindex,
107 __call = __call,
108 __tostring = __tostring,
109 })
110 end
111 end
112
113 function AceLocale:new(name)
114 error(MAJOR_VERSION .. " is not supported in WoW 2.0", 2)
115 self:argCheck(name, 2, "string")
116
117 if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then
118 return self.registry[name]
119 end
120
121 local self = {
122 [__strictness__] = false,
123 [__name__] = name,
124 }
125 refixInstance(self)
126
127 AceLocale.registry[name] = self
128 return self
129 end
130
131 setmetatable(AceLocale, { __call = AceLocale.new })
132
133 AceLocale.prototype = {}
134 AceLocale.prototype.class = AceLocale
135
136 function AceLocale.prototype:EnableDebugging()
137 if rawget(self, __baseTranslations__) then
138 AceLocale:error("Cannot enable debugging after a translation has been registered.")
139 end
140 rawset(self, __debugging__, true)
141 end
142
143 function AceLocale.prototype:RegisterTranslations(locale, func)
144 AceLocale.argCheck(self, locale, 2, "string")
145 AceLocale.argCheck(self, func, 3, "function")
146
147 if locale == rawget(self, __baseLocale__) then
148 AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
149 end
150
151 if rawget(self, __baseTranslations__) and GetLocale() ~= locale then
152 if rawget(self, __debugging__) then
153 local t = func()
154 func = nil
155 if type(t) ~= "table" then
156 AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
157 end
158 self[__translationTables__][locale] = t
159 t = nil
160 end
161 func = nil
162 return
163 end
164 local t = func()
165 func = nil
166 if type(t) ~= "table" then
167 AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
168 end
169
170 rawset(self, __translations__, t)
171 if not rawget(self, __baseTranslations__) then
172 rawset(self, __baseTranslations__, t)
173 rawset(self, __baseLocale__, locale)
174 for key,value in pairs(t) do
175 if value == true then
176 t[key] = key
177 end
178 end
179 else
180 for key, value in pairs(self[__translations__]) do
181 if not rawget(self[__baseTranslations__], key) then
182 AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale)
183 end
184 if value == true then
185 AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, __baseLocale__), locale)
186 end
187 end
188 end
189 refixInstance(self)
190 if rawget(self, __debugging__) then
191 if not rawget(self, __translationTables__) then
192 rawset(self, __translationTables__, {})
193 end
194 self[__translationTables__][locale] = t
195 end
196 t = nil
197 end
198
199 function AceLocale.prototype:SetStrictness(strict)
200 AceLocale.argCheck(self, strict, 2, "boolean")
201 local mt = getmetatable(self)
202 if not mt then
203 AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.")
204 end
205 if not rawget(self, __translations__) then
206 AceLocale.error(self, "No translations registered.")
207 end
208 rawset(self, __strictness__, strict)
209 refixInstance(self)
210 end
211
212 function AceLocale.prototype:GetTranslationStrict(text, sublevel)
213 AceLocale.argCheck(self, text, 1, "string")
214 local translations = rawget(self, __translations__)
215 if not translations then
216 AceLocale.error(self, "No translations registered")
217 end
218 if sublevel then
219 local t = rawget(translations, text)
220 if type(t) ~= "table" then
221 AceLocale.error(self, "Strict translation %q::%q does not exist", text, sublevel)
222 end
223 local value = t[sublevel]
224 if not value then
225 AceLocale.error(self, "Strict translation %q::%q does not exist", text, sublevel)
226 end
227 return value
228 else
229 local value = rawget(translations, text)
230 if not value then
231 AceLocale.error(self, "Strict translation %q does not exist", text)
232 end
233 return value
234 end
235 end
236
237 function AceLocale.prototype:GetTranslation(text, sublevel)
238 AceLocale.argCheck(self, text, 1, "string")
239 local translations = rawget(self, __translations__)
240 if not translations then
241 AceLocale.error(self, "No translations registered")
242 end
243 if sublevel then
244 local base = self[__baseTranslations__]
245 local standard = rawget(translations, text)
246 local current
247 local baseStandard
248 if not standard then
249 baseStandard = rawget(base, text)
250 current = baseStandard
251 end
252 if not type(current) ~= "table" then
253 AceLocale.error(self, "Loose translation %q::%q does not exist", text, sublevel)
254 end
255 local value = current[sublevel]
256 if not value then
257 if current == baseStandard or type(baseStandard) ~= "table" then
258 AceLocale.error(self, "Loose translation %q::%q does not exist", text, sublevel)
259 end
260 value = baseStandard[sublevel]
261 if not value then
262 AceLocale.error(self, "Loose translation %q::%q does not exist", text, sublevel)
263 end
264 end
265 return value
266 else
267 local value = rawget(translations, text)
268 if not value then
269 AceLocale.error(self, "Loose translation %q does not exist", text)
270 end
271 return value
272 end
273 end
274
275 local function initReverse(self)
276 rawset(self, __reverseTranslations__, {})
277 local alpha = self[__translations__]
278 local bravo = self[__reverseTranslations__]
279 for base, localized in pairs(alpha) do
280 bravo[localized] = base
281 end
282 end
283
284 function AceLocale.prototype:GetReverseTranslation(text)
285 local x = rawget(self, __reverseTranslations__)
286 if not x then
287 if not rawget(self, __translations__) then
288 AceLocale.error(self, "No translations registered")
289 end
290 initReverse(self)
291 x = self[__reverseTranslations__]
292 end
293 local translation = x[text]
294 if not translation then
295 AceLocale.error(self, "Reverse translation for %q does not exist", text)
296 end
297 return translation
298 end
299
300 function AceLocale.prototype:GetIterator()
301 local x = rawget(self, __translations__)
302 if not x then
303 AceLocale.error(self, "No translations registered")
304 end
305 return next, x, nil
306 end
307
308 function AceLocale.prototype:GetReverseIterator()
309 local x = rawget(self, __reverseTranslations__)
310 if not x then
311 if not rawget(self, __translations__) then
312 AceLocale.error(self, "No translations registered")
313 end
314 initReverse(self)
315 x = self[__reverseTranslations__]
316 end
317 return next, x, nil
318 end
319
320 function AceLocale.prototype:HasTranslation(text, sublevel)
321 AceLocale.argCheck(self, text, 1, "string")
322 local x = rawget(self, __translations__)
323 if not x then
324 AceLocale.error(self, "No translations registered")
325 end
326 if sublevel then
327 AceLocale.argCheck(self, sublevel, 2, "string", "nil")
328 return type(rawget(x, text)) == "table" and x[text][sublevel] and true
329 end
330 return rawget(x, text) and true
331 end
332
333 function AceLocale.prototype:HasReverseTranslation(text)
334 local x = rawget(self, __reverseTranslations__)
335 if not x then
336 if not rawget(self, __translations__) then
337 AceLocale.error(self, "No translations registered")
338 end
339 initReverse(self)
340 x = self[__reverseTranslations__]
341 end
342 return x[text] and true
343 end
344
345 AceLocale.prototype.GetTableStrict = AceLocale.prototype.GetTranslationStrict
346 AceLocale.prototype.GetTable = AceLocale.prototype.GetTranslation
347
348 function AceLocale.prototype:Debug()
349 if not rawget(self, __debugging__) then
350 return
351 end
352 local words = {}
353 local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW"}
354 local localizations = {}
355 DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---")
356 for _,locale in ipairs(locales) do
357 if not self[__translationTables__][locale] then
358 DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale))
359 else
360 localizations[locale] = self[__translationTables__][locale]
361 end
362 end
363 local localeDebug = {}
364 for locale, localization in pairs(localizations) do
365 localeDebug[locale] = {}
366 for word in pairs(localization) do
367 if type(localization[word]) == "table" then
368 if type(words[word]) ~= "table" then
369 words[word] = {}
370 end
371 for bit in pairs(localization[word]) do
372 if type(localization[word][bit]) == "string" then
373 words[word][bit] = true
374 end
375 end
376 elseif type(localization[word]) == "string" then
377 words[word] = true
378 end
379 end
380 end
381 for word in pairs(words) do
382 if type(words[word]) == "table" then
383 for bit in pairs(words[word]) do
384 for locale, localization in pairs(localizations) do
385 if not rawget(localization, word) or not localization[word][bit] then
386 localeDebug[locale][word .. "::" .. bit] = true
387 end
388 end
389 end
390 else
391 for locale, localization in pairs(localizations) do
392 if not rawget(localization, word) then
393 localeDebug[locale][word] = true
394 end
395 end
396 end
397 end
398 for locale, t in pairs(localeDebug) do
399 if not next(t) then
400 DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale))
401 else
402 DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale))
403 for word in pairs(t) do
404 DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word))
405 end
406 end
407 end
408 DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---")
409 end
410
411 setmetatable(AceLocale.prototype, {
412 __index = function(self, k)
413 if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later.
414 AceLocale.error(lastSelf or self, "Translation %q does not exist.", k)
415 end
416 return nil
417 end
418 })
419
420 local function activate(self, oldLib, oldDeactivate)
421 AceLocale = self
422
423 if oldLib then
424 self.registry = oldLib.registry
425 self.__baseTranslations__ = oldLib.__baseTranslations__
426 self.__debugging__ = oldLib.__debugging__
427 self.__translations__ = oldLib.__translations__
428 self.__baseLocale__ = oldLib.__baseLocale__
429 self.__translationTables__ = oldLib.__translationTables__
430 self.__reverseTranslations__ = oldLib.__reverseTranslations__
431 self.__strictness__ = oldLib.__strictness__
432 self.__name__ = oldLib.__name__
433 end
434 if not self.__baseTranslations__ then
435 self.__baseTranslations__ = {}
436 end
437 if not self.__debugging__ then
438 self.__debugging__ = {}
439 end
440 if not self.__translations__ then
441 self.__translations__ = {}
442 end
443 if not self.__baseLocale__ then
444 self.__baseLocale__ = {}
445 end
446 if not self.__translationTables__ then
447 self.__translationTables__ = {}
448 end
449 if not self.__reverseTranslations__ then
450 self.__reverseTranslations__ = {}
451 end
452 if not self.__strictness__ then
453 self.__strictness__ = {}
454 end
455 if not self.__name__ then
456 self.__name__ = {}
457 end
458
459 __baseTranslations__ = self.__baseTranslations__
460 __debugging__ = self.__debugging__
461 __translations__ = self.__translations__
462 __baseLocale__ = self.__baseLocale__
463 __translationTables__ = self.__translationTables__
464 __reverseTranslations__ = self.__reverseTranslations__
465 __strictness__ = self.__strictness__
466 __name__ = self.__name__
467
468 if not self.registry then
469 self.registry = {}
470 else
471 for name, instance in pairs(self.registry) do
472 local name = name
473 local mt = getmetatable(instance)
474 setmetatable(instance, nil)
475 instance[__name__] = name
476 local strict
477 if instance.translations then
478 instance[__translations__], instance.translations = instance.translations
479 instance[__baseLocale__], instance.baseLocale = instance.baseLocale
480 instance[__baseTranslations__], instance.baseTranslations = instance.baseTranslations
481 instance[__debugging__], instance.debugging = instance.debugging
482 instance.reverseTranslations = nil
483 instance[__translationTables__], instance.translationTables = instance.translationTables
484 if mt and mt.__call == oldLib.prototype.GetTranslationStrict then
485 strict = true
486 end
487 else
488 if instance[__strictness__] ~= nil then
489 strict = instance[__strictness__]
490 elseif instance[__translations__] ~= instance[__baseTranslations__] then
491 if getmetatable(instance[__translations__]).__index == oldLib.prototype then
492 strict = true
493 end
494 end
495 end
496 instance[__strictness__] = strict and true or false
497 refixInstance(instance)
498 end
499 end
500
501 if oldDeactivate then
502 oldDeactivate(oldLib)
503 end
504 end
505
506 AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)