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