--[[ Name: AceLocale-2.0 Revision: $Rev: 4519 $ Author(s): ckknight (ckknight@gmail.com) Website: http://www.wowace.com/ Documentation: http://wiki.wowace.com/index.php/AceLocale-2.0 SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.0 Description: Localization library for addons to use to handle proper localization and internationalization. Dependencies: AceLibrary ]] local MAJOR_VERSION = "AceLocale-2.0" local MINOR_VERSION = "$Revision: 4519 $" if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end local AceLocale = {} local DEFAULT_LOCALE = "enUS" local _G = getfenv(0) local stage = 3 if tonumber(date("%Y%m%d")) < 20060714 then stage = 1 elseif tonumber(date("%Y%m%d")) < 20060721 then stage = 2 end if stage <= 2 then function AceLocale:new(name, strict, baseLocale) self:argCheck(name, 2, "string") self:argCheck(strict, 3, "boolean", "nil") self:argCheck(baseLocale, 4, "string", "nil") if self.registry[name] and type(self.registry[name].GetLibraryVersion) ~= "function" then return self.registry[name] end local self = setmetatable({}, { __index = self.prototype, __call = strict and self.prototype.GetTranslationStrict or self.prototype.GetTranslation, __tostring = function(self) if type(self.GetLibraryVersion) == "function" then return self:GetLibraryVersion() else return "AceLocale(" .. name .. ")" end end }) if not baseLocale then baseLocale = DEFAULT_LOCALE end if type(_G[name .. "_Locale_" .. baseLocale]) ~= "function" then AceLocale.registry[name] = self return self -- ;-) end local locale = GetLocale() local func = _G[name .. "_Locale_" .. locale] if strict then if type(func) == "function" then self.translations = func() elseif func == nil then self.translations = {} end else if type(func) ~= "function" then func = _G[name .. "_Locale_" .. baseLocale] end self.translations = func() end if type(self.translations) ~= "table" then AceLocale.error(self, "You have not provided adequate translations. You must at least have global function %s that returns a translation table.", name .. "_Locale_" .. baseLocale) end if func == _G[name .. "_Locale_" .. baseLocale] then self.baseTranslations = self.translations else self.baseTranslations = _G[name .. "_Locale_" .. baseLocale]() end if type(self.baseTranslations) ~= "table" then AceLocale.error(self, "You have not provided adequate translations. You must at least have global function %s that returns a translation table.", name .. "_Locale_" .. baseLocale) end if locale ~= baseLocale then for key in pairs(self.translations) do if not self.baseTranslations[key] then AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) break end end end _G[name .. "_Locale_enUS"] = nil _G[name .. "_Locale_deDE"] = nil _G[name .. "_Locale_frFR"] = nil _G[name .. "_Locale_zhCN"] = nil _G[name .. "_Locale_zhTW"] = nil _G[name .. "_Locale_koKR"] = nil AceLocale.registry[name] = self return self end else function AceLocale:new(name) self:argCheck(name, 2, "string") if self.registry[name] and type(self.registry[name].GetLibraryVersion) ~= "function" then return self.registry[name] end local self = setmetatable({}, { __index = self.prototype, __call = self.prototype.GetTranslation, __tostring = function(self) if type(self.GetLibraryVersion) == "function" then return self:GetLibraryVersion() else return "AceLocale(" .. name .. ")" end end }) AceLocale.registry[name] = self return self end end setmetatable(AceLocale, { __call = AceLocale.new }) AceLocale.prototype = {} AceLocale.prototype.class = AceLocale function AceLocale.prototype:EnableDebugging() if self.baseTranslations then AceLocale.error(self, "Cannot enable debugging after a translation has been registered.") end self.debugging = true end function AceLocale.prototype:RegisterTranslations(locale, func) AceLocale.argCheck(self, locale, 2, "string") AceLocale.argCheck(self, func, 3, "function") if self.baseTranslations and GetLocale() ~= locale then if self.debugging then local t = func() func = nil if type(t) ~= "table" then AceLocale.error(self, "Bad argument #3 to `RegisterTranslation'. function did not return a table. (expected table, got %s)", type(t)) end self.translationTables[locale] = t t = nil end func = nil collectgarbage() return end local t = func() func = nil if type(t) ~= "table" then AceLocale.error(self, "Bad argument #3 to `RegisterTranslation'. function did not return a table. (expected table, got %s)", type(t)) end self.translations = t if not self.baseTranslations then self.baseTranslations = t self.baseLocale = locale for key,value in pairs(self.baseTranslations) do if value == true then self.baseTranslations[key] = key end end else for key, value in pairs(self.translations) do if not self.baseTranslations[key] then AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) elseif value == true then AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", self.baseLocale, locale) end end end if self.debugging then if not self.translationTables then self.translationTables = {} end self.translationTables[locale] = t end t = nil collectgarbage() end function AceLocale.prototype:SetStrictness(strict) local mt = getmetatable(self) if not mt then AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.") end if strict then mt.__call = self.GetTranslationStrict else mt.__call = self.GetTranslation end end function AceLocale.prototype:GetTranslationStrict(text, sublevel) AceLocale.argCheck(self, text, 1, "string") AceLocale.assert(self, self.translations, "No translations registered") if not self.translations then AceLocale.error(self, "No translations registered") end if sublevel then AceLocale.argCheck(self, sublevel, 2, "string") local t = self.translations[text] if type(t) ~= "table" then if type(self.baseTranslations[text]) == "table" then AceLocale.error(self, "%q::%q has not been translated into %q", text, sublevel, locale) return else AceLocale.error(self, "Translation for %q::%q does not exist", text, sublevel) return end end local translation = t[sublevel] if type(translation) ~= "string" then if type(self.baseTranslations[text]) == "table" then if type(self.baseTranslations[text][sublevel]) == "string" then AceLocale.error(self, "%q::%q has not been translated into %q", text, sublevel, locale) return else AceLocale.error(self, "Translation for %q::%q does not exist", text, sublevel) return end else AceLocale.error(self, "Translation for %q::%q does not exist", text, sublevel) return end end return translation end local translation = self.translations[text] if type(translation) ~= "string" then if type(self.baseTranslations[text]) == "string" then AceLocale.error(self, "%q has not been translated into %q", text, locale) return else AceLocale.error(self, "Translation for %q does not exist", text) return end end return translation end function AceLocale.prototype:GetTranslation(text, sublevel) AceLocale:argCheck(text, 1, "string") AceLocale.assert(self, self.translations, "No translations registered") if sublevel then AceLocale:argCheck(sublevel, 2, "string", "nil") local t = self.translations[text] if type(t) == "table" then local translation = t[sublevel] if type(translation) == "string" then return translation else t = self.baseTranslations[text] if type(t) ~= "table" then AceLocale.error(self, "Translation table %q does not exist", text) return end translation = t[sublevel] if type(translation) ~= "string" then AceLocale.error(self, "Translation for %q::%q does not exist", text, sublevel) return end return translation end else t = self.baseTranslations[text] if type(t) ~= "table" then AceLocale.error(self, "Translation table %q does not exist", text) return end local translation = t[sublevel] if type(translation) ~= "string" then AceLocale.error(self, "Translation for %q::%q does not exist", text, sublevel) return end return translation end end local translation = self.translations[text] if type(translation) == "string" then return translation else translation = self.baseTranslations[text] if type(translation) ~= "string" then AceLocale.error(self, "Translation for %q does not exist", text) return end return translation end end local function initReverse(self) self.reverseTranslations = {} local alpha = self.translations local bravo = self.reverseTranslations for base, localized in pairs(alpha) do bravo[localized] = base end end function AceLocale.prototype:GetReverseTranslation(text) AceLocale.argCheck(self, text, 1, "string") AceLocale.assert(self, self.translations, "No translations registered") if not self.reverseTranslations then initReverse(self) end local translation = self.reverseTranslations[text] if type(translation) ~= "string" then AceLocale.error(self, "Reverse translation for %q does not exist", text) return end return translation end function AceLocale.prototype:GetIterator() AceLocale.assert(self, self.translations, "No translations registered") return pairs(self.translations) end function AceLocale.prototype:GetReverseIterator() AceLocale.assert(self, self.translations, "No translations registered") if not self.reverseTranslations then initReverse(self) end return pairs(self.reverseTranslations) end function AceLocale.prototype:HasTranslation(text, sublevel) AceLocale.argCheck(self, text, 1, "string") if sublevel then AceLocale.argCheck(self, sublevel, 2, "string", "nil") return type(self.translations[text]) == "table" and self.translations[text][sublevel] and true end return self.translations[text] and true end function AceLocale.prototype:HasReverseTranslation(text) if not self.reverseTranslations then initReverse(self) end return self.reverseTranslations[text] and true end function AceLocale.prototype:GetTableStrict(key, key2) AceLocale.argCheck(self, key, 1, "string") AceLocale.assert(self, self.translations, "No translations registered") if key2 then AceLocale.argCheck(self, key2, 2, "string") local t = self.translations[key] if type(t) ~= "table" then if type(self.baseTranslations[key]) == "table" then AceLocale.error(self, "%q::%q has not been translated into %q", key, key2, locale) return else AceLocale.error(self, "Translation table %q::%q does not exist", key, key2) return end end local translation = t[key2] if type(translation) ~= "table" then if type(self.baseTranslations[key]) == "table" then if type(self.baseTranslations[key][key2]) == "table" then AceLocale.error(self, "%q::%q has not been translated into %q", key, key2, locale) return else AceLocale.error(self, "Translation table %q::%q does not exist", key, key2) return end else AceLocale.error(self, "Translation table %q::%q does not exist", key, key2) return end end return translation end local translation = self.translations[key] if type(translation) ~= "table" then if type(self.baseTranslations[key]) == "table" then AceLocale.error(self, "%q has not been translated into %q", key, locale) return else AceLocale.error(self, "Translation table %q does not exist", key) return end end return translation end function AceLocale.prototype:GetTable(key, key2) AceLocale.argCheck(self, key, 1, "string") AceLocale.assert(self, self.translations, "No translations registered") if key2 then AceLocale.argCheck(self, key2, 2, "string", "nil") local t = self.translations[key] if type(t) == "table" then local translation = t[key2] if type(translation) == "table" then return translation else t = self.baseTranslations[key] if type(t) ~= "table" then AceLocale.error(self, "Translation table %q does not exist", key) return end translation = t[key2] if type(translation) ~= "table" then AceLocale.error(self, "Translation table %q::%q does not exist", key, key2) return end return translation end else t = self.baseTranslations[key] if type(t) ~= "table" then AceLocale.error(self, "Translation table %q does not exist", key) return end local translation = t[key2] if type(translation) ~= "table" then AceLocale.error(self, "Translation table %q::%q does not exist", key, key2) return end return translation end end local translation = self.translations[key] if type(translation) == "table" then return translation else translation = self.baseTranslations[key] if type(translation) ~= "table" then AceLocale.error(self, "Translation table %q does not exist", key) return end return translation end end function AceLocale.prototype:Debug() if not self.debugging then return end local words = {} local locales = {"enUS", "deDE", "frFR", "zhCN", "zhTW", "koKR"} local localizations = {} DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---") for _,locale in ipairs(locales) do if not self.translationTables[locale] then DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale)) else localizations[locale] = self.translationTables[locale] end end local localeDebug = {} for locale, localization in pairs(localizations) do localeDebug[locale] = {} for word in pairs(localization) do if type(localization[word]) == "table" then if type(words[word]) ~= "table" then words[word] = {} end for bit in pairs(localization[word]) do if type(localization[word][bit]) == "string" then words[word][bit] = true end end elseif type(localization[word]) == "string" then words[word] = true end end end for word in pairs(words) do if type(words[word]) == "table" then for bit in pairs(words[word]) do for locale, localization in pairs(localizations) do if not localization[word] or not localization[word][bit] then localeDebug[locale][word .. "::" .. bit] = true end end end else for locale, localization in pairs(localizations) do if not localization[word] then localeDebug[locale][word] = true end end end end for locale, t in pairs(localeDebug) do if not next(t) then DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale)) else DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale)) for word in pairs(t) do DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word)) end end end DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---") end local function activate(self, oldLib, oldDeactivate) AceLocale = self if oldLib then self.registry = oldLib.registry end if not self.registry then self.registry = {} end if oldDeactivate then oldDeactivate(oldLib) end end AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate) AceLocale = AceLibrary(MAJOR_VERSION)