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