Jump to content

Module:dercat

From Wiktionary, the free dictionary

Used by {{dercat}}.


local export = {}

local etymology_module = "Module:etymology"
local parameters_module = "Module:parameters"
local utilities_module = "Module:utilities"

local insert = table.insert
local require = require

--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
	local function check_ancestor(...)
		check_ancestor = require(etymology_module).check_ancestor
		return check_ancestor(...)
	end
	
	local function format_categories(...)
		format_categories = require(utilities_module).format_categories
		return format_categories(...)
	end
	
	local function process_params(...)
		process_params = require(parameters_module).process
		return process_params(...)
	end

local function language_or_string(val)
	return val == "<" and "string" or "language"
end

function export.dercat(frame)
	local args = process_params(frame:getParent().args, {
		[1] = {required = true, type = "full language"},
		[2] = {list = true, required = true, type = language_or_string, family = true},
		["inh"] = {type = "number"},
	})

	local target_lang, langs, categories, cutoff = args[1], args[2], {}
	local target_lang_code, target_lang_name = target_lang:getCode(), target_lang:getCanonicalName()
	
	for i = 1, #langs do
		local source_lang = langs[i]
		if source_lang == "<" then
			-- Disallow "inh" and "<" together.
			if args.inh then
				error(("Cannot specify parameter \"inh\" if \"<\" has been set (see parameter %d): use one or the other."):format(i))
			-- Disallow multiple "<"s.
			elseif cutoff then
				-- Collate keys for all "<"s in the input; all keys need to be offset by 1, since args[1] isn't in the table.
				local lt = {cutoff + 1, i + 1}
				while langs[i] do
					i = i + 1
					if langs[i] == "<" then
						insert(lt, i + 1)
					end
				end
				error(("Cannot specify \"<\" more than once, but currently used in parameters %s."):format(mw.text.listToText(lt)))
			end
			cutoff = i
			-- Add inheritance categories for all languages encountered so far.
			for j = 1, i - 1 do
				local inh_source_lang = langs[j]
				check_ancestor(target_lang, inh_source_lang)
				insert(categories, j * 2, target_lang_name .. " terms inherited from " .. inh_source_lang:getDisplayForm())
			end
		else
			-- Generate the "derived from" category, accounting for the special case when a language derives from itself.
			-- Note: "borrowed back into" uses :getCanonicalName(), while the other categories use :getDisplayForm().
			insert(categories, target_lang_name .. " terms " .. (target_lang_code == source_lang:getCode() and
					"borrowed back into " .. source_lang:getCanonicalName() or
					"derived from " .. source_lang:getDisplayForm()
			))
			if args.inh and i <= args.inh then
				check_ancestor(target_lang, source_lang)
				insert(categories, target_lang_name .. " terms inherited from " .. source_lang:getDisplayForm())
			end
		end
	end
	return format_categories(categories, target_lang)
end

return export