Zerotorescue@0: --- **AceLocale-3.0** manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings. Zerotorescue@0: -- @class file Zerotorescue@0: -- @name AceLocale-3.0 Zerotorescue@0: -- @release $Id: AceLocale-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ Zerotorescue@0: local MAJOR,MINOR = "AceLocale-3.0", 2 Zerotorescue@0: Zerotorescue@0: local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR) Zerotorescue@0: Zerotorescue@0: if not AceLocale then return end -- no upgrade needed Zerotorescue@0: Zerotorescue@0: -- Lua APIs Zerotorescue@0: local assert, tostring, error = assert, tostring, error Zerotorescue@0: local setmetatable, rawset, rawget = setmetatable, rawset, rawget Zerotorescue@0: Zerotorescue@0: -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded Zerotorescue@0: -- List them here for Mikk's FindGlobals script Zerotorescue@0: -- GLOBALS: GAME_LOCALE, geterrorhandler Zerotorescue@0: Zerotorescue@0: local gameLocale = GetLocale() Zerotorescue@0: if gameLocale == "enGB" then Zerotorescue@0: gameLocale = "enUS" Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: AceLocale.apps = AceLocale.apps or {} -- array of ["AppName"]=localetableref Zerotorescue@0: AceLocale.appnames = AceLocale.appnames or {} -- array of [localetableref]="AppName" Zerotorescue@0: Zerotorescue@0: -- This metatable is used on all tables returned from GetLocale Zerotorescue@0: local readmeta = { Zerotorescue@0: __index = function(self, key) -- requesting totally unknown entries: fire off a nonbreaking error and return key Zerotorescue@0: rawset(self, key, key) -- only need to see the warning once, really Zerotorescue@0: geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'") Zerotorescue@0: return key Zerotorescue@0: end Zerotorescue@0: } Zerotorescue@0: Zerotorescue@0: -- This metatable is used on all tables returned from GetLocale if the silent flag is true, it does not issue a warning on unknown keys Zerotorescue@0: local readmetasilent = { Zerotorescue@0: __index = function(self, key) -- requesting totally unknown entries: return key Zerotorescue@0: rawset(self, key, key) -- only need to invoke this function once Zerotorescue@0: return key Zerotorescue@0: end Zerotorescue@0: } Zerotorescue@0: Zerotorescue@0: -- Remember the locale table being registered right now (it gets set by :NewLocale()) Zerotorescue@0: -- NOTE: Do never try to register 2 locale tables at once and mix their definition. Zerotorescue@0: local registering Zerotorescue@0: Zerotorescue@0: -- local assert false function Zerotorescue@0: local assertfalse = function() assert(false) end Zerotorescue@0: Zerotorescue@0: -- This metatable proxy is used when registering nondefault locales Zerotorescue@0: local writeproxy = setmetatable({}, { Zerotorescue@0: __newindex = function(self, key, value) Zerotorescue@0: rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string Zerotorescue@0: end, Zerotorescue@0: __index = assertfalse Zerotorescue@0: }) Zerotorescue@0: Zerotorescue@0: -- This metatable proxy is used when registering the default locale. Zerotorescue@0: -- It refuses to overwrite existing values Zerotorescue@0: -- Reason 1: Allows loading locales in any order Zerotorescue@0: -- Reason 2: If 2 modules have the same string, but only the first one to be Zerotorescue@0: -- loaded has a translation for the current locale, the translation Zerotorescue@0: -- doesn't get overwritten. Zerotorescue@0: -- Zerotorescue@0: local writedefaultproxy = setmetatable({}, { Zerotorescue@0: __newindex = function(self, key, value) Zerotorescue@0: if not rawget(registering, key) then Zerotorescue@0: rawset(registering, key, value == true and key or value) Zerotorescue@0: end Zerotorescue@0: end, Zerotorescue@0: __index = assertfalse Zerotorescue@0: }) Zerotorescue@0: Zerotorescue@0: --- Register a new locale (or extend an existing one) for the specified application. Zerotorescue@0: -- :NewLocale will return a table you can fill your locale into, or nil if the locale isn't needed for the players Zerotorescue@0: -- game locale. Zerotorescue@0: -- @paramsig application, locale[, isDefault[, silent]] Zerotorescue@0: -- @param application Unique name of addon / module Zerotorescue@0: -- @param locale Name of the locale to register, e.g. "enUS", "deDE", etc. Zerotorescue@0: -- @param isDefault If this is the default locale being registered (your addon is written in this language, generally enUS) Zerotorescue@0: -- @param silent If true, the locale will not issue warnings for missing keys. Can only be set on the default locale. Zerotorescue@0: -- @usage Zerotorescue@0: -- -- enUS.lua Zerotorescue@0: -- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "enUS", true) Zerotorescue@0: -- L["string1"] = true Zerotorescue@0: -- Zerotorescue@0: -- -- deDE.lua Zerotorescue@0: -- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "deDE") Zerotorescue@0: -- if not L then return end Zerotorescue@0: -- L["string1"] = "Zeichenkette1" Zerotorescue@0: -- @return Locale Table to add localizations to, or nil if the current locale is not required. Zerotorescue@0: function AceLocale:NewLocale(application, locale, isDefault, silent) Zerotorescue@0: Zerotorescue@0: if silent and not isDefault then Zerotorescue@0: error("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' can only be specified for the default locale", 2) Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: -- GAME_LOCALE allows translators to test translations of addons without having that wow client installed Zerotorescue@0: -- Ammo: I still think this is a bad idea, for instance an addon that checks for some ingame string will fail, just because some other addon Zerotorescue@0: -- gives the user the illusion that they can run in a different locale? Ditch this whole thing or allow a setting per 'application'. I'm of the Zerotorescue@0: -- opinion to remove this. Zerotorescue@0: local gameLocale = GAME_LOCALE or gameLocale Zerotorescue@0: Zerotorescue@0: if locale ~= gameLocale and not isDefault then Zerotorescue@0: return -- nop, we don't need these translations Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: local app = AceLocale.apps[application] Zerotorescue@0: Zerotorescue@0: if not app then Zerotorescue@0: app = setmetatable({}, silent and readmetasilent or readmeta) Zerotorescue@0: AceLocale.apps[application] = app Zerotorescue@0: AceLocale.appnames[app] = application Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: registering = app -- remember globally for writeproxy and writedefaultproxy Zerotorescue@0: Zerotorescue@0: if isDefault then Zerotorescue@0: return writedefaultproxy Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: return writeproxy Zerotorescue@0: end Zerotorescue@0: Zerotorescue@0: --- Returns localizations for the current locale (or default locale if translations are missing). Zerotorescue@0: -- Errors if nothing is registered (spank developer, not just a missing translation) Zerotorescue@0: -- @param application Unique name of addon / module Zerotorescue@0: -- @param silent If true, the locale is optional, silently return nil if it's not found (defaults to false, optional) Zerotorescue@0: -- @return The locale table for the current language. Zerotorescue@0: function AceLocale:GetLocale(application, silent) Zerotorescue@0: if not silent and not AceLocale.apps[application] then Zerotorescue@0: error("Usage: GetLocale(application[, silent]): 'application' - No locales registered for '"..tostring(application).."'", 2) Zerotorescue@0: end Zerotorescue@0: return AceLocale.apps[application] Zerotorescue@0: end