Jump to content

Module:I18n

From Wikisource

i18n stands for internationalisation, because it is formed by i + 18 letters + n. This modules serves as the basis for the various localisation templates. Data submodules:


--[[
Backbone of various internationalisation templates.
--]]

local p = {}

local function normalize_args(frame)
	return require('Module:Arguments').getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
end

--[[
Returns the user's selected UI language if none was stated.
* `frame` (optional): Can be specified in order to avoid the module from retrieving it again.
* `stated_lang` (optional): Manually specified language.
--]]
local function get_lang(frame, spec_lang)
	if not spec_lang or not mw.language.isSupportedLanguage(spec_lang) then
		return (frame or mw.getCurrentFrame()):callParserFunction("int", "lang")
	end
	return spec_lang
end

--[[
Iterates until it finds a supported language.
* `start_lang`: The best language possible from which the fallback chain starts.
* `check`: The method called to check whether a language has support or not.
* `found`: The method called when a supported language is finally found.
--]]
local function fallback(start_lang, check, found)
	-- Return error if there is not default and no English version.
	if not check("en") and not check("default") and not check("message") and not check("item") then
		return error("Fallback, no default option provided.")
	end
	-- Iterate through each language in the fallback list.
	local lang_list = mw.language.getFallbacksFor(start_lang)
	table.insert(lang_list, 1, start_lang)
	table.insert(lang_list, "message")
	table.insert(lang_list, "item")
	table.insert(lang_list, "default")
	for _, lang in ipairs(lang_list) do
		if check(lang) then
			return found(lang)
		end
	end
end

--[[
Returns the message in the most appropriate language.
* `data`:  Data table of translations.
* `start_lang`: Language to translate to (either stated or user's default).
--]]
local function from_data(data, start_lang)
	return fallback(
		start_lang,
		function (lang) return data[lang] end,
		function (lang)
			local value = data[lang]
			-- The tilde works as a fallback-stopping nil value.
			if value == "~" then
				return nil, lang
			end
			-- Wikidata items.
			if lang == "item" then
				return (mw.wikibase.getLabelWithLang(value)) or value
			end
			-- Interface messages.
			if lang == "message" then
				return tostring(mw.message.new(value):inLanguage(start_lang))
			end
			-- Normal case scenario.
			return value
		end
	)
end

-- Method called by {{int table}}.
function p.int_table(frame)
	local args = normalize_args(frame)
	local lang = get_lang(frame, args.lang)
	args.lang = nil
	return from_data(args, lang)
end

-- Method called by {{int page}}.
function p.int_page(frame)
	local args = normalize_args(frame)
	args.lang = get_lang(frame, args.lang)
	-- Find base page.
	local base = args.base
	assert(base, "Autotranslate, base page not provided")
	args.base = nil
	-- If base page does not indicate namespace assume it is a template.
	if not mw.ustring.find(base, ":") then
		base = "Template:" .. base
	end
	-- Find language subpage.
	local page = (fallback(
		args.lang,
		function(lang) return mw.title.new(base .. "/" .. lang).exists end,
		function (lang) return base .. "/" .. lang end
	-- Default page if provided or nil otherwise.
	)) or args.default
	-- Transclude with template arguments the same as the ones passed to {{autotranslate}} template.
	-- TODO: Track whether these args are ever useful and remove if not.
	return frame:expandTemplate { title = page, args = args }
end

-- Method called by {{int}}.
function p.int_word(frame)
	local args = normalize_args(frame)
	return from_data(
		require("Module:i18n/data/" .. args[1]),
		get_lang(frame, args.lang)
	)
end

-- Method called by {{int langname}}.
function p.int_langname(frame)
	local code = normalize_args(frame)[1]
	local name = mw.language.fetchLanguageName(code, get_lang(frame))
	return name == "" and code or name
end

return p