Module:gender and number

Documentatie voor deze module kan aangemaakt worden op de volgende pagina: Module:gender and number/doc

--[=[
	Deze module maakt gestandaardiseerde notaties voor grammaticale categorieën zoals geslacht en aantal.
	Hij zet een specificatie om in HTML-formaat.

	Een specificatie bestaat uit een of meer elementen, gescheiden door streepjes.
	Voorbeelden zijn: "n" (onzijdig geslacht), "f-p" (vrouwelijk meervoud), "m-an-p" (mannelijk bezield meervoud),
	"pf" (perfectief aspect). Elk element heeft de volgende eigenschappen:
	1. Een code, zoals gebruikt in de specificatie, bijvoorbeeld "f" voor vrouwelijk, "p" voor meervoud.
	2. Een type, bijvoorbeeld "geslacht", "getal" of "bezieling".
	   Elk element in een bepaalde specificatie moet van een ander type zijn.
	3. Een weergavevorm, die op zijn beurt bestaat uit een weergavecode en een tooltip.
	   De weergavecode mag anders zijn dan de specificatiecode, bijvoorbeeld
	   de specificatiecode "f" heeft de weergavecode "v" en de tooltip "vrouwelijk geslacht".
]=]--

local export = {}
local codes = {
	["?"] = {type = "overig", display = '<abbr title="geslacht incompleet">?</abbr>'},

-- Geslachten
	["m"] = {type = "geslacht", display = '<abbr title="mannelijk geslacht">m</abbr>'},
	["f"] = {type = "geslacht", display = '<abbr title="vrouwelijk geslacht">v</abbr>'},
	["n"] = {type = "geslacht", display = '<abbr title="onzijdig geslacht">o</abbr>'},
	["c"] = {type = "geslacht", display = '<abbr title="gemeenschappelijk geslacht">g</abbr>'},

-- Bezieling
	["an"] = {type = "bezieling", display = '<abbr title="bezield">bezield</abbr>'},
	["in"] = {type = "bezieling", display = '<abbr title="onbezield">onbezield</abbr>'},
	["anml"] = {type = "bezieling", display = '<abbr title="dierlijk">dierlijk</abbr>'},
	["pr"] = {type = "bezieling", display = '<abbr title="persoonlijk">pers</abbr>'},
	["np"] = {type = "bezieling", display = '<abbr title="onpersoonlijk">onpers</abbr>'},

-- Viriliteit
	["vr"] = {type = "viriliteit", display = '<abbr title="viriel">vir</abbr>'},
	["nv"] = {type = "viriliteit", display = '<abbr title="non-viriel">nvir</abbr>'},

-- Getallen
	["s"] = {type = "getal", display = '<abbr title="enkelvoudig getal">enk</abbr>'},
	["d"] = {type = "getal", display = '<abbr title="tweevoudig getal">tv</abbr>'},
	["p"] = {type = "getal", display = '<abbr title="meervoudig getal">mv</abbr>'},

-- Werkwoordskwalificaties
	["impf"] = {type = "aspect", display = '<abbr title="imperfectief aspect">impf</abbr>'},
	["pf"] = {type = "aspect", display = '<abbr title="perfectief aspect">pf</abbr>'},
}


-- Entry point that can be invoked from a template.
function export.show_list(frame)
	local args = frame.args
	local list = {}
	local i = 1

	while args[i] and args[i] ~= "" do
		table.insert(list, args[i])
		i = i + 1
	end

	return export.format_genders(list)
end


-- Format one or more gender/number specifications. Each spec is either a string, e.g. "f-p", or
-- a table of the form {spec = "SPEC"} where `.spec` is a gender/number spec such as "f-p".
-- The function returns the formatted text.
function export.format_genders(specs)
	local formatted_specs = {}
	local seen_types = {}
	local all_is_nounclass = nil

	local function do_gender_spec(spec, parts)
		local types = {}

		for key, code in ipairs(parts) do
			-- Is this code valid?
			if not codes[code] then
				error('Het label "' .. code .. '" in de specificatie "' .. spec.spec .. '" is ongeldig.')
			end

			-- Check for multiple genders/numbers/animacies in a single spec.
			local typ = codes[code].type
			if typ ~= "other" and types[typ] then
				error('De specificatie "' .. spec.spec .. '" bevat meerdere labels van het type "' .. typ .. '".')
			end
			types[typ] = true

			parts[key] = codes[code].display
		end

		-- Add the processed codes together with non-breaking spaces
		if #parts == 1 then
			return parts[1]
		end
		return table.concat(parts, "&nbsp;")
	end

	for _, spec in ipairs(specs) do
		if type(spec) ~= "table" then
			spec = {spec = spec}
		end
		local is_nounclass
		-- If the specification starts with cX, then it is a noun class specification.
		if spec.spec:find("^[1-9]") or spec.spec:find("^c[^-]") then
			is_nounclass = true
			code = spec.spec:gsub("^c", "")

			local text
			if code == "?" then
				text = '<abbr title="naamwoordklasse incompleet">?</abbr>'
			else
				text = '<abbr title="naamwoordklasse ' .. code .. '">' .. code .. "</abbr>"
			end
			table.insert(formatted_specs, text)
		else
			-- Split the parts and iterate over each part, converting it into its display form
			local parts = mw.text.split(spec.spec, "%-")

			table.insert(formatted_specs, do_gender_spec(spec, parts))

			is_nounclass = false
		end

		-- Ensure that the specifications are either all noun classes, or none are.
		if all_is_nounclass == nil then
			all_is_nounclass = is_nounclass
		elseif all_is_nounclass ~= is_nounclass then
			error("Klassen en geslachten van naamwoorden kunnen niet worden gecombineerd. Gebruik een van de twee.")
		end
	end

	if is_nounclass then
		-- Add the processed codes together with slashes
		return '<span class="gender" style="font-style:italic">klasse ' .. table.concat(formatted_specs, "/") .. "</span>"
	else
		-- Add the processed codes together with " of "
		return '<span class="gender" style="font-style:italic">' .. table.concat(formatted_specs, " of ") .. "</span>"
	end
end

return export