Modul:Sandkasse/Poul G/I18n

Fra Wikipedia, den frie encyklopædi
Jump to navigation Jump to search
Documentation icon Moduldokumentation[opret]
-- I18n deals with messages in order to make modules language-independent. A module should be able to
-- place messages in sub-modules named like Module:Modulename/i18n/fr for french messages.


local loaded = {} -- cache, filename to table or "not found"

-- helper to cache loadData
-- pagename: the page to load
-- returns a table or nil
local function load(pagename)
	-- mw.log('load ' .. pagename)
	local ret = loaded[pagename]
	if ret == "not found" then
		return nil
	elseif ret == nil then -- first try
		local status
		status, ret = pcall(mw.loadData, pagename)
		if not status then
			loaded[pagename] = "not found"
			return nil
		end
		loaded[pagename] = ret
		-- mw.log(pagename.." loaded "..type(ret)..": "..mw.dumpObject(ret))
	end
	-- mw.log('load returns ' .. mw.dumpObject(ret))
	return ret
end


-- helper to lookup a keyvalue
-- lst: the list of table to search; strings will trigger mw.loadData
-- key: the key to lookup
-- validate: function to filter found values; by default everything is accepted
-- nomatch: function to return a value if everyting else fails; by default nil
-- returns the first value acceptable by validate
local function lookup(lst,key,validate,nomatch)
	-- sanatize parameters
	lst = lst or {}
	if type(key) == "number" then
		key = tostring(key)
	elseif type(key) ~= "string" then
		return error("i18n.lookup(non string argument)",2)
	elseif key == "" then
		return error("i18n.lookup(empty string argument)",2)
	end
	if type(validate) ~= "function" then
		validate = function(key, value) return true end
	end
	if type(nomatch) ~= "function" then
		nomatch = function(key) return nil end
	end
	-- loop over lst; stop at first match
	for n, tbl in pairs(lst) do
		-- mw.log("work on (" .. n .. ") " .. mw.dumpObject(tbl))
		if type(tbl) == "string" then
			-- mw.log('load it')
			tbl = load(tbl) -- will return a table or nil
			lst[n] = tbl -- save for next lookup
			-- mw.log('loaded '..tostring(tbl))
		end
		if type(tbl) == "table" and tbl[key] and validate(key, tbl[key]) then
			return tbl[key]
		end
	end
	return nomatch(key)
end


local I18n = {} -- table to export class with callable functions

function I18n.new(start)
	local i18n, mt, lst = {}, {}, {} -- instance, its metatable, holder of searchlist
	
	-- appends table or module-name to the search-list
	i18n.append = function(tbl)
		if type(tbl) == "table" then
			lst[#lst+1] = tbl -- append to search-list
		elseif type(tbl) == "string" then
			if mw.ustring.sub(tbl,-1) ~= "/" then
				tbl = tbl .. "/"
			end
			local lang = mw.language.getContentLanguage()
			if lang then
				lang = lang.code
			else
				lang = "en" -- use english as last default fallback
			end
			-- append the names of the modules to load; loading is done when actually needed
			lst[#lst+1] = tbl .. "i18n/" .. lang
			for _, fallbackLang in pairs(mw.language.getFallbacksFor(lang)) do
				lst[#lst+1] = tbl .. "i18n/" .. fallbackLang
			end
		else
			return error("invalid tbl-parameter for i18n.append, expected table or pagename, found "..type(tbl), 2)
		end
		return i18n -- allow chaining
	end
	
	-- wraps error message in error-class span
	i18n.error = function(key)
		local value
		if type(key) == "string" and key ~= "" then
			value = i18n[key] or "undefined error: " .. key
		else
			value = "error"
		end
		local elm = mw.html.create('span')
		elm
			:addClass('error')
			:wikitext(value)
		return tostring(elm)
	end

	mt.__call = function(tbl,...)
		local args = {...}
		return lookup(lst,args[1])
	end

	mt.__concat = function(a,b)
		a.append(b)
		return a
	end

	mt.__index = function(tbl,key)
		return lookup(lst,key)
	end

	-- block updates
	mt.__newindex = function(tbl,key,value)
		return error("attempted modify of i18n["..key.."]", 2)
	end

	setmetatable(i18n,mt)
	
	if start then
		i18n.append(start)
	end

	return i18n
end


return I18n