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