vanilla-wow-addons – Blame information for rev 1

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