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