Module:vep-nominals

From Wiktionary, the free dictionary
Jump to navigation Jump to search

This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local m_utilities = require("Module:utilities")
local m_links = require("Module:links")

local export = {}

local lang = require("Module:languages").getByCode("vep")

-- Functions that do the actual inflecting by creating the forms of a basic term.
local inflections = {}

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local infl_type = frame.args[1] or error("Inflection type has not been specified. Please pass parameter 1 to the module invocation")
	local args = frame:getParent().args
	
	if not inflections[infl_type] then
		error("Unknown inflection type '" .. infl_type .. "'")
	end
	
	local data = {forms = {}, title = mw.title.getCurrentTitle().text, info = nil, categories = {}}
	data.n = args["n"]; if data.n == "" then data.n = nil end
	
	if mw.title.getCurrentTitle().namespace == 10 then
		data.title = args["title"] or data.title
	end

    local lemma = data.title
    if args["suffix"] and #args["suffix"] > 0 then
        local suffix = args["suffix"]
        if mw.ustring.sub(lemma, -mw.ustring.len(suffix)) ~= suffix then
            error("|suffix= does not match the lemma")
        end
        lemma = mw.ustring.sub(lemma, 1, -mw.ustring.len(suffix) - 1)
    end
    data.lemma = lemma
	
	-- Generate the forms
	inflections[infl_type](args, data)
	
	-- Postprocess
	if infl_type ~= "ppron" then
		postprocess(args, data)
	end
	
	return make_table(data) .. m_utilities.format_categories(data.categories, lang)
end


--[=[
	Inflection functions
]=]--

local function get_param(args, first, default)
	default = default or ""
	local param = args[first] or default
	
	if param == default and mw.title.getCurrentTitle().namespace == 10 then
		return "{{{" .. first .. "}}}"
	end
	
	return param
end

local function append(stems, suffix)
	local result = {}
	for _, stem in ipairs(stems) do
		table.insert(result, stem .. suffix)
	end
	return result
end

local function shorten_illative(stem, ending)
	if mw.ustring.match(ending, "^h") and mw.ustring.match(stem, "[aeiouäöü]$") then
		return mw.ustring.sub(stem, 1, -2)
	end
	-- return nothing
end

inflections["ppron"] = function(args, data)
	local person = args[1]
	
	if not person or person == "" then
		error("Please specify the person, 1, 2 or 3.")
	else
		person = tonumber(person)
	end
	
	local sg_letter
	local sg
	local pl
	
	if person == 1 then
		sg_letter = "m"
		sg = "minu"
		pl = "m"
	elseif person == 2 then
		sg_letter = "s"
		sg = "sinu"
		pl = "t"
	elseif person == 3 then
		sg_letter = "h"
		sg = "häne"
		pl = "h"
	end
	
	data.forms["nom_sg"] = {person == 3 and "hän" or sg_letter .. "inä"}
	data.forms["acc_sg"] = {sg .. "n"}
	data.forms["gen_sg"] = {sg .. "n"}
	data.forms["par_sg"] = {person == 3 and "händast" or sg_letter .. "indai"}
	
	data.forms["ine_sg"] = {sg .. "s"}
	data.forms["ela_sg"] = {sg .. "späi"}
	data.forms["ill_sg"] = {sg .. "h" .. (person == 3 and "e" or "u")}
	
	data.forms["ade_sg"] = {person == 3 and "hänel" or sg_letter .. "inai"}
	data.forms["abl_sg"] = {person == 3 and "hänelpäi" or sg_letter .. "inaipäi"}
	data.forms["all_sg"] = {person == 3 and "hänele" or sg_letter .. "inei"}
	
	data.forms["abe_sg"] = {sg .. "ta"}
	data.forms["com_sg"] = {sg .. "nke"}
	
	data.forms["nom_pl"] = {pl .. "ö"}
	data.forms["acc_pl"] = {pl .. "ö"}
	data.forms["gen_pl"] = {pl .. "eiden"}
	data.forms["par_pl"] = {pl .. "eid"}
	
	data.forms["ine_pl"] = {pl .. "eiš"}
	data.forms["ela_pl"] = {pl .. "eišpäi"}
	data.forms["ill_pl"] = {pl .. "eihe"}
	
	data.forms["ade_pl"] = {pl .. "eil"}
	data.forms["abl_pl"] = {pl .. "eilpäi"}
	data.forms["all_pl"] = {pl .. "eile"}
	
	data.forms["abe_pl"] = {pl .. "eita"}
	data.forms["com_pl"] = {pl .. "eidenke"}
end

inflections["ken"] = function(args, data)
	data.forms["nom_sg"] = {"ken"}
	data.forms["acc_sg"] = {"kenen"}
	data.forms["gen_sg"] = {"kenen"}
	data.forms["par_sg"] = {"keda"}
	data.forms["ess_sg"] = {"kenen"}
	data.forms["tra_sg"] = {"keneks"}
	
	data.forms["ine_sg"] = {"kes", "kenes"}
	data.forms["ela_sg"] = {"kespäi", "kenespäi"}
	data.forms["ill_sg"] = {"kehe", "kenehe"}
	
	data.forms["ade_sg"] = {"kel", "kenel"}
	data.forms["abl_sg"] = {"kelpäi", "kenelpäi"}
	data.forms["all_sg"] = {"kelle", "kenele"}
	
	data.forms["abe_sg"] = {"keneta"}
	data.forms["com_sg"] = {"kenenke"}
	data.forms["pro_sg"] = {"kedame"}
	
	data.forms["ap1_sg"] = {"kenenno"}
	data.forms["ap2_sg"] = {"kenennoks"}
	data.forms["egr_sg"] = {"kenennopäi"}
	
	data.forms["te1_sg"] = {"kehesai", "kenehesai"}
	data.forms["te2_sg"] = {"kellesai", "kenelesai"}
	
	data.forms["ad1_sg"] = {"kehepäi", "kenehepäi"}
	data.forms["ad2_sg"] = {"kellepäi", "kenelepäi"}
	
	if args["prefix"] == "" and args["suffix"] == "" then
		data.forms["nom_pl"] = {"ked"}
	end
end

inflections["mi"] = function(args, data)
	data.forms["nom_sg"] = {"mi"}
	data.forms["acc_sg"] = {"min"}
	data.forms["gen_sg"] = {"min"}
	data.forms["par_sg"] = {"midä"}
	data.forms["ess_sg"] = {"min"}
	data.forms["tra_sg"] = {"mikš"}
	
	data.forms["ine_sg"] = {"miš"}
	data.forms["ela_sg"] = {"mišpäi"}
	data.forms["ill_sg"] = {"mihe"}
	
	data.forms["ade_sg"] = {"mil"}
	data.forms["abl_sg"] = {"milpäi"}
	data.forms["all_sg"] = {"mille"}
	
	data.forms["abe_sg"] = {"mita"}
	data.forms["com_sg"] = {"minke"}
	data.forms["pro_sg"] = {"midäme"}
	
	data.forms["ap1_sg"] = {"minno"}
	data.forms["ap2_sg"] = {"minnoks"}
	data.forms["egr_sg"] = {"minnopäi"}
	
	data.forms["te1_sg"] = {"mihesai"}
	data.forms["te2_sg"] = {"millesai"}
	
	data.forms["ad1_sg"] = {"mihepäi"}
	data.forms["ad2_sg"] = {"millepäi"}
	
	if args["prefix"] == "" and args["suffix"] == "" then
		data.forms["nom_pl"] = {"mid"}
	end
end

inflections["se"] = function(args, data)
	-- Singular
	data.forms["nom_sg"] = {"se"}
	data.forms["acc_sg"] = {"sen"}
	data.forms["gen_sg"] = {"sen"}
	data.forms["par_sg"] = {"sidä"}
	data.forms["ess_sg"] = {"sen"}
	data.forms["tra_sg"] = {"sikš"}
	
	data.forms["ine_sg"] = {"siš"}
	data.forms["ela_sg"] = {"sišpäi"}
	data.forms["ill_sg"] = {"sihe"}
	
	data.forms["ade_sg"] = {"sil"}
	data.forms["abl_sg"] = {"silpäi"}
	data.forms["all_sg"] = {"sile"}
	
	data.forms["abe_sg"] = {"sita"}
	data.forms["com_sg"] = {"senke"}
	data.forms["pro_sg"] = {"sidäme"}
	
	data.forms["ap1_sg"] = {"senno"}
	data.forms["ap2_sg"] = {"sennoks"}
	data.forms["egr_sg"] = {"sennopäi"}
	
	data.forms["te1_sg"] = {"sihesai"}
	data.forms["te2_sg"] = {"silesai"}
	
	data.forms["ad1_sg"] = {"sihepäi"}
	data.forms["ad2_sg"] = {"silepäi"}
	
	-- Plural
	data.forms["nom_pl"] = {"ne", "ned"}
	data.forms["acc_pl"] = {"ne", "ned"}
	data.forms["gen_pl"] = {"niiden"}
	data.forms["par_pl"] = {"niid"}
	data.forms["ess_pl"] = nil
	data.forms["tra_pl"] = {"niikš"}
	
	data.forms["ine_pl"] = {"niiš"}
	data.forms["ela_pl"] = {"niišpäi"}
	data.forms["ill_pl"] = {"niihe"}
	
	data.forms["ade_pl"] = {"niil"}
	data.forms["abl_pl"] = {"niilpäi"}
	data.forms["all_pl"] = {"niile"}
	
	data.forms["abe_pl"] = {"niita"}
	data.forms["com_pl"] = {"niidenke"}
	data.forms["pro_pl"] = {"niidme"}
	
	data.forms["ap1_pl"] = {"niidenno"}
	data.forms["ap2_pl"] = {"niidennoks"}
	data.forms["egr_pl"] = {"niidennopäi"}
	
	data.forms["te1_pl"] = {"niihesai"}
	data.forms["te2_pl"] = {"niilesai"}
	data.forms["te3_pl"] = nil
	
	data.forms["ad1_pl"] = {"niihepäi"}
	data.forms["ad2_pl"] = {"niilepäi"}
end

inflections["nece"] = function(args, data)
	-- Singular
	data.forms["nom_sg"] = {"nece"}
	data.forms["acc_sg"] = {"necen"}
	data.forms["gen_sg"] = {"necen"}
	data.forms["par_sg"] = {"necidä"}
	data.forms["ess_sg"] = {"necen"}
	data.forms["tra_sg"] = {"necikš"}
	
	data.forms["ine_sg"] = {"neciš"}
	data.forms["ela_sg"] = {"necišpäi"}
	data.forms["ill_sg"] = {"neche"}
	
	data.forms["ade_sg"] = {"necil"}
	data.forms["abl_sg"] = {"necilpäi"}
	data.forms["all_sg"] = {"necile"}
	
	data.forms["abe_sg"] = {"necita"}
	data.forms["com_sg"] = {"necenke"}
	data.forms["pro_sg"] = {"necidäme"}
	
	data.forms["ap1_sg"] = {"necenno"}
	data.forms["ap2_sg"] = {"necennoks"}
	data.forms["egr_sg"] = {"necennopäi"}
	
	data.forms["te1_sg"] = {"nechesai"}
	data.forms["te2_sg"] = {"necilesai"}
	
	data.forms["ad1_sg"] = {"nechepäi"}
	data.forms["ad2_sg"] = {"necilepäi"}
	
	-- Plural
	data.forms["nom_pl"] = {"nene", "nened"}
	data.forms["acc_pl"] = {"nene", "nened"}
	data.forms["gen_pl"] = {"neniden"}
	data.forms["par_pl"] = {"nenid"}
	data.forms["ess_pl"] = nil
	data.forms["tra_pl"] = {"nenikš"}
	
	data.forms["ine_pl"] = {"neniš"}
	data.forms["ela_pl"] = {"nenišpäi"}
	data.forms["ill_pl"] = {"nenihe"}
	
	data.forms["ade_pl"] = {"nenil"}
	data.forms["abl_pl"] = {"nenilpäi"}
	data.forms["all_pl"] = {"nenile"}
	
	data.forms["abe_pl"] = {"nenita"}
	data.forms["com_pl"] = {"nenidenke"}
	data.forms["pro_pl"] = {"nenidme"}
	
	data.forms["ap1_pl"] = {"nenidenno"}
	data.forms["ap2_pl"] = {"nenidennoks"}
	data.forms["egr_pl"] = {"nenidennopäi"}
	
	data.forms["te1_pl"] = {"nenihesai"}
	data.forms["te2_pl"] = {"nenilesai"}
	data.forms["te3_pl"] = nil
	
	data.forms["ad1_pl"] = {"nenihepäi"}
	data.forms["ad2_pl"] = {"nenilepäi"}
end

--[=[
	New auto-inflection types
]=]--

local function add_info(data, number, specimen)
	data.info = "inflection type " .. number .. "/" .. m_links.full_link({lang = lang, term = specimen}, "term")
	table.insert(data.categories, lang:getCanonicalName() .. " " .. specimen .. "-type nominals")
end

local function extract_stem(stem, suffix)
	local result = mw.ustring.match(stem, suffix .. "$")
	if not result then
		error("Unsupported stem for this inflection type")
	end
	return mw.ustring.gsub(stem, suffix .. "$", ""), result
end

local function get_final_consonant(stem)
	local stem, final = mw.ustring.match(stem, "(.-)([^aeiouäöü]'?)$")
	if not stem then
		error("Unsupported stem for this inflection type")
	end
	return stem, final
end

-- short_ill_type (nil = 0: none, 1: common, 2: rare)
local DEFAULT_SHORT_ILL_FILTER = "[cčflstz][aeiouüäö]$"
local function generate_from_stems(args, data, nom_sg, gen_sg, par_sg, par_pl, short_ill_type, short_ill_filter)
	local palatalize_sg = mw.ustring.find(gen_sg, "i$")
	local palatalize_pl = mw.ustring.find(par_pl, "i$")
    local ill_sg = gen_sg

	local s_sg = palatalize_sg and "š" or "s"
	local s_pl = palatalize_pl and "š" or "s"

	local ill_sg_ending, ill_pl_ending
	
	short_ill_type = short_ill_type or 0
	if short_ill_type > 0 and short_ill_filter and not mw.ustring.find(ill_sg, short_ill_filter) then
		short_ill_type = 0
	end

	if mw.ustring.find(gen_sg, "h[aeiouäöü]+$") then
		ill_sg_ending = palatalize_sg and "že" or "ze"
	else
		local vowel = mw.ustring.match(gen_sg, "([aeiouäöü])$") or "a"
		ill_sg_ending = "h" .. (vowel == "i" and "e" or vowel)
	end

	if mw.ustring.find(par_pl, "h[aeiouäöü]+$") then
		ill_pl_ending = mw.ustring.find(par_pl, "i$") and "že" or "ze"
	elseif n ~= "sg" then
		local vowel = mw.ustring.match(par_pl, "([aeiouäöü])$") or "i"
		ill_pl_ending = "h" .. (vowel == "i" and "e" or vowel)
	end
	
	local short_ill
	if short_ill_type > 0 then
		local alt_stem = shorten_illative(ill_sg, ill_sg_ending)
		if alt_stem then
			short_ill = alt_stem .. ill_sg_ending
		end
	end
	
	-- Singular
	data.forms["nom_sg"] = {nom_sg}
	data.forms["acc_sg"] = {gen_sg .. "n"}
	data.forms["gen_sg"] = {gen_sg .. "n"}
	data.forms["par_sg"] = {par_sg}
	data.forms["ess_sg"] = {gen_sg .. "n"}
	data.forms["tra_sg"] = {gen_sg .. "k" .. s_sg}
	
	data.forms["ine_sg"] = {gen_sg .. s_sg}
	data.forms["ela_sg"] = {gen_sg .. s_sg .. "päi"}
	data.forms["ill_sg"] = {ill_sg .. ill_sg_ending}
	if short_ill then table.insert(data.forms["ill_sg"], short_ill_type, short_ill) end
	
	data.forms["ade_sg"] = {gen_sg .. "l"}
	data.forms["abl_sg"] = {gen_sg .. "lpäi"}
	data.forms["all_sg"] = {gen_sg .. "le"}
	
	data.forms["abe_sg"] = {gen_sg .. "ta"}
	data.forms["com_sg"] = {gen_sg .. "nke"}
	data.forms["pro_sg"] = {par_sg .. "me"}
	
	data.forms["ap1_sg"] = {gen_sg .. "nno"}
	data.forms["ap2_sg"] = {gen_sg .. "nnoks"}
	data.forms["egr_sg"] = {gen_sg .. "nnopäi"}
	
	data.forms["te1_sg"] = append(data.forms["ill_sg"], "sai")
	data.forms["te2_sg"] = {gen_sg .. "lesai"}
	data.forms["te3_sg"] = {gen_sg .. "ssai"}
	
	data.forms["ad1_sg"] = append(data.forms["ill_sg"], "päi")
	data.forms["ad2_sg"] = {gen_sg .. "lepäi"}
	
	-- Plural
	data.forms["nom_pl"] = {gen_sg .. "d"}
	data.forms["acc_pl"] = {gen_sg .. "d"}
	data.forms["gen_pl"] = {par_pl .. "den"}
	data.forms["par_pl"] = {par_pl .. "d"}
	data.forms["ess_pl"] = {par_pl .. "n"}
	data.forms["tra_pl"] = {par_pl .. "k" .. s_pl}
	
	data.forms["ine_pl"] = {par_pl .. s_pl}
	data.forms["ela_pl"] = {par_pl .. s_pl .. "päi"}
	data.forms["ill_pl"] = {par_pl .. ill_pl_ending}
	
	data.forms["ade_pl"] = {par_pl .. "l"}
	data.forms["abl_pl"] = {par_pl .. "lpäi"}
	data.forms["all_pl"] = {par_pl .. "le"}
	
	data.forms["abe_pl"] = {par_pl .. "ta"}
	data.forms["com_pl"] = {par_pl .. "denke"}
	data.forms["pro_pl"] = {par_pl .. "dme"}
	
	data.forms["ap1_pl"] = {par_pl .. "denno"}
	data.forms["ap2_pl"] = {par_pl .. "dennoks"}
	data.forms["egr_pl"] = {par_pl .. "dennopäi"}
	
	data.forms["te1_pl"] = {par_pl .. ill_pl_ending .. "sai"}
	data.forms["te2_pl"] = {par_pl .. "lesai"}
	data.forms["te3_pl"] = nil
	
	data.forms["ad1_pl"] = {par_pl .. ill_pl_ending .. "päi"}
	data.forms["ad2_pl"] = {par_pl .. "lepäi"}
end

inflections["ilo"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "[ouöü]$") then
		error("A stem ending in -o, -u, -ö, -ü, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 1, "ilo")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem .. "i",
			1, DEFAULT_SHORT_ILL_FILTER)
end

inflections["samal"] = function(args, data)
	local stem = data.lemma
	local vowel = args[1] or error("The final vowel must be provided.")
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
    else
		stem = extract_stem(stem, "[aä]l'?") .. "l" .. vowel
	end
	add_info(data, 1, "samal")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem .. "i",
			1, DEFAULT_SHORT_ILL_FILTER)
end

inflections["kodi"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "i$") then
		error("A stem ending in -i, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 2, "kodi")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem,
			1, DEFAULT_SHORT_ILL_FILTER)
end

inflections["kivi"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "e$") then
		error("A stem ending in -e, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 3, "kivi")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", mw.ustring.sub(stem, 1, -2) .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["meri"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "e$") then
		error("A stem ending in -e, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 4, "meri")
	local part_stem
	if mw.ustring.find(data.lemma, "i$") then
		part_stem = mw.ustring.sub(stem, 1, -2) .. "t"
	else
		part_stem = data.lemma .. "t"
	end
	return generate_from_stems(args, data, data.lemma,
			stem, part_stem, mw.ustring.sub(stem, 1, -2) .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["sana"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "[aä]$") then
		error("A stem ending in -a or -ä, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 5, "sana")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", mw.ustring.sub(stem, 1, -2) .. "oi",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["kuva"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "[aä]$") then
		error("A stem ending in -a or -ä, equivalent to the genitive singular without the final -n, must be specified.")
	end
	add_info(data, 6, "kuva")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", mw.ustring.gsub(mw.ustring.gsub(mw.ustring.sub(stem, 1, -2), "'$", ""), "([^aeiouäöü])j$", "%1jj") .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["pedai"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "jad") .. "ja"
	else
		stem = extract_stem(stem, "i") .. "ja"
	end
	add_info(data, 7, "pedai")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", mw.ustring.sub(stem, 1, -2) .. "i", 0)
end

inflections["abai"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	else
		stem = extract_stem(stem, "i") .. "jo"
	end
	add_info(data, 8, "abai")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem.. "i", 0)
end

inflections["čai"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	else
		stem = extract_stem(stem, "i") .. "ju"
	end
	add_info(data, 9, "čai")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem .. "i", 0)
end

inflections["Biblii"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ad")
	else
		stem = extract_stem(stem, "i") .. "j"
	end
	add_info(data, 10, "Biblii")
	return generate_from_stems(args, data, data.lemma,
			stem .. "a", stem .. "ad", stem .. "oi", 0)
end

inflections["kofe"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	end
	add_info(data, 11, "kofe")
	return generate_from_stems(args, data, data.lemma,
			stem, stem .. "d", stem .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["korged"] = function(args, data)
	local stem = data.lemma
	local strong, weak
	if data.n == "pl" then
		stem = extract_stem(stem, "tad")
	else
		stem = extract_stem(stem, "ed")
		if mw.ustring.match(stem, "[ht]k$") then
			stem = stem
		else
			stem = mw.ustring.sub(stem, 1, -2) .. ({g = "k", k = "t"})[mw.ustring.sub(stem, -1, -1)] or error("Unsupported word for type 8")
		end
	end
	add_info(data, 12, "korged")
	return generate_from_stems(args, data, data.lemma,
			stem .. "ta", stem .. "ta", stem .. "toi", 0)
end

inflections["ma"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	end
	local pl_stem = mw.ustring.gsub(stem .. "i", "ii$", "i")
	add_info(data, 13, "ma")
	return generate_from_stems(args, data, data.lemma, stem, stem .. "d", pl_stem, 0)
end

inflections["lumi"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	else
		if mw.ustring.find(stem, "[i']$") then
			stem = mw.ustring.sub(stem, 1, -2)
		end
		stem = stem .. "e"
	end
	if not mw.ustring.find(stem, "me$") then
		error("Unsupported word for type 10")
	end
	stem = mw.ustring.sub(stem, 1, -3)
	add_info(data, 14, "lumi")
	return generate_from_stems(args, data, data.lemma,
			stem .. "me", stem .. "nt", stem .. "mi",
            2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["kümne"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	end
	stem = extract_stem(stem, "e")
	add_info(data, 15, "kümne")
	return generate_from_stems(args, data, data.lemma,
			stem .. "e", stem .. "ed", stem .. "i", 0)
end

inflections["katuz"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ed")
	else
		local final
		stem, final = get_final_consonant(stem)
		if final == "z'" then
			stem = stem .. "z"
		elseif mw.ustring.match(final, "[sz]'?") then
			stem = stem .. "s"
		else
			error("Unsupported stem for type 12")
		end
	end
	add_info(data, 16, "katuz")
	return generate_from_stems(args, data, data.lemma,
			stem .. "e", stem .. "t", stem .. "i", 0)
end

inflections["laps'"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ed")
	else
		stem = mw.ustring.gsub(stem, "'$", "")
	end
	stem = extract_stem(stem, "ps")
	add_info(data, 17, "laps'")
	return generate_from_stems(args, data, data.lemma,
			stem .. "pse", stem .. "st", stem .. "psi", 0)
end

inflections["vezi"] = function(args, data)
	local stem = data.lemma
	local z = "z"
	if data.n == "pl" then
		stem = extract_stem(stem, "ded")
	else
		local final
		stem, final = extract_stem(stem, "[szž]['i]?")
		if mw.ustring.find(final, "ž") then z = "ž" end
	end
	add_info(data, 18, "vezi")
	return generate_from_stems(args, data, data.lemma,
			stem .. "de", stem .. "t", stem .. z .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["veič"] = function(args, data)
	local stem = data.lemma
	local final
	if data.n == "pl" then
		stem, final = extract_stem(stem, "i[cč]ed")
	else
		stem, final = extract_stem(stem, "i[cč]'?")
	end
	local strong = "c"
	local weak = "s"
	if mw.ustring.find(final, "č") then strong, weak = "č", "š" end
	add_info(data, 19, "veič")
	return generate_from_stems(args, data, data.lemma,
			stem .. "i" .. strong .. "e", stem .. weak .. "t", stem .. "i" .. strong .. "i",
			2, DEFAULT_SHORT_ILL_FILTER)
end

inflections["üks'"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "hted")
	else
		stem = extract_stem(stem, "ks'?")
	end
	add_info(data, 20, "üks'")
	return generate_from_stems(args, data, data.lemma,
			stem .. "hte", stem .. "ht", stem .. "ksi", 0)
end

inflections["sizar"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ed")
	end
	add_info(data, 21, "sizar")
	return generate_from_stems(args, data, data.lemma,
			stem .. "e", stem .. "t", stem .. "i", 0)
end

inflections["homen"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ned")
    else
		stem = extract_stem(stem, "en")
	end
	add_info(data, 22, "homen")
	return generate_from_stems(args, data, data.lemma,
			stem .. "ne", stem .. "ent", stem .. "ni", 0)
end

inflections["tütär"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "red")
    else
		stem = extract_stem(stem, "[aä]r'?")
	end
	add_info(data, 23, "tütär")
	return generate_from_stems(args, data, data.lemma,
			stem .. "re", data.lemma .. "t", stem .. "ri", 0)
end

inflections["südäin"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "imed")
    else
		stem = extract_stem(stem, "in")
	end
	add_info(data, 24, "südäin")
	return generate_from_stems(args, data, data.lemma,
			stem .. "ime", stem .. "nt", stem .. "imi", 0)
end

inflections["pähkim"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "med")
    else
		stem = extract_stem(stem, "im")
	end
	add_info(data, 25, "pähkim")
	return generate_from_stems(args, data, data.lemma,
			stem .. "me", stem .. "int", stem .. "mi", 0)
end

inflections["holetoi"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "mad")
    else
		stem = extract_stem(stem, "i")
	end
	add_info(data, 26, "holetoi")
	return generate_from_stems(args, data, data.lemma,
			stem .. "ma", stem .. "nt", stem .. "mi", 0)
end

inflections["toine"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ižed")
    else
		stem = extract_stem(stem, "ine")
	end
	add_info(data, 27, "toine")
	return generate_from_stems(args, data, data.lemma,
			stem .. "iže", stem .. "št", stem .. "iži",
			2, nil)
end

inflections["sinine"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "žed")
    else
		stem = extract_stem(stem, "ne")
	end
	add_info(data, 28, "sinine")
	return generate_from_stems(args, data, data.lemma,
			stem .. "že", stem .. "št", stem .. "ži", 0)
end

inflections["lambaz"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "had")
    else
		stem = mw.ustring.gsub(extract_stem(stem, "az"), "([kpt])%1$", "%1")
	end
	add_info(data, 29, "lambaz")
	local stem_h = mw.ustring.gsub(stem, "z$", "s")
	return generate_from_stems(args, data, data.lemma,
			mw.ustring.gsub(stem_h, "h$", "") .. "ha", stem .. "ast", stem_h .. "hi", 0)
end

inflections["kunigaz"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "had")
    else
		stem = extract_stem(stem, "z")
	end
	add_info(data, 30, "kunigaz")
	return generate_from_stems(args, data, data.lemma,
			stem .. "ha", stem .. "st", stem .. "hi", 0)
end

inflections["kirvez"] = function(args, data)
	local c_stem, v_stem, par_stem
	if data.n == "pl" then
		v_stem = extract_stem(data.lemma, "d")
        c_stem = extract_stem(v_stem, "[ae]")
        par_stem = v_stem
    else
        local stem, final = extract_stem(data.lemma, "[zž]")
        par_stem = stem .. ({["z"] = "s", ["ž"] = "š"})[final]
        if args["i"] then
        	c_stem, v_stem = stem, "i"
        else
        	c_stem, v_stem = extract_stem(stem, "[aäei]")
        end
        c_stem = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(c_stem, "'$", ""), "l$", ""), "kk$", "k") .. "h"
        v_stem = c_stem .. mw.ustring.gsub(v_stem, "i", "e")
	end
	add_info(data, 31, "kirvez")
	return generate_from_stems(args, data, data.lemma,
			v_stem, par_stem .. "t", c_stem .. "i", 0)
end

inflections["mez'"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "hed")
    else
		stem = extract_stem(stem, "z'")
	end
	add_info(data, 32, "mez'")
	return generate_from_stems(args, data, data.lemma,
			stem .. "he", stem .. "st", stem .. "hi", 0)
end

inflections["olut"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ded")
    else
		stem = extract_stem(stem, "[td]")
	end
	add_info(data, 33, "olut")
	return generate_from_stems(args, data, data.lemma,
			stem .. "de", stem .. "t", stem .. "zi", 0)
end

inflections["kolnu"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "d")
	end
	add_info(data, 34, "kolnu")
	return generate_from_stems(args, data, data.lemma,
			stem .. "de", stem .. "t", stem .. "zi", 0)
end

inflections["kuverz'"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "dad")
    else
		stem = extract_stem(stem, "z'?")
	end
	add_info(data, 35, "kuverz'")
	return generate_from_stems(args, data, data.lemma,
			stem .. "da", stem .. "t", stem .. "zi", 0)
end

inflections["kaste"] = function(args, data)
	local stem = args[1]
	if not stem or not mw.ustring.find(stem, "e$") then
		error("A stem ending in -e, equivalent to the genitive singular without the final -n, must be specified.")
	end
    stem = extract_stem(stem, "e")
	add_info(data, 36, "kaste")
	return generate_from_stems(args, data, data.lemma,
			stem .. "e", data.lemma .. "t", stem .. "i", 0)
end

inflections["terveh"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "hed")
    else
		stem = extract_stem(stem, "eh")
	end
	add_info(data, 37, "terveh")
	return generate_from_stems(args, data, data.lemma,
			stem .. "he", stem .. "eht", stem .. "hi", 0)
end

inflections["mitte"] = function(args, data)
	local stem = data.lemma
	if data.n == "pl" then
		stem = extract_stem(stem, "ččed")
    else
		stem = extract_stem(stem, "tte")
	end
	add_info(data, 38, "mitte")
	return generate_from_stems(args, data, data.lemma,
			stem .. "čče", stem .. "ttušt", stem .. "čči", 2, nil)
end

-- Helper functions

function postprocess(args, data)
	local prefix = args["prefix"] or ""
	local suffix = args["suffix"] or ""
	
	for key, form in pairs(data.forms) do
		-- Do not show singular or plural forms for nominals that don't have them
		if (data.n == "pl" and key:find("_sg$")) or (data.n == "sg" and key:find("_pl$")) then
			form = nil
		elseif form then
			for key2, subform in pairs(form) do
				form[key2] = prefix .. subform .. suffix
			end
		end
		
		data.forms[key] = form
	end
	
	-- Check if the lemma form matches the page name
	local lemma_key = data.n == "pl" and "nom_pl" or "nom_sg"
	
	if data.forms[lemma_key] and data.forms[lemma_key][1] and (lang:makeEntryName(data.forms[lemma_key][1])) ~= mw.title.getCurrentTitle().text then
		table.insert(data.categories, lang:getCanonicalName() .. " entries with inflection not matching pagename")
	end
end

-- Make the table
function make_table(data)
	local function show_form(form)
		if not form then
			return "—"
		end
		
		if type(form) ~= "table" then
			error("a non-table value was given in the list of inflected forms.")
		end
		
		local ret = {}
		
		for key, subform in ipairs(form) do
			if mw.ustring.find(subform, "?", nil, true) then
				table.insert(ret, "?")
			else
				table.insert(ret, m_links.full_link({lang = lang, term = subform}))
			end
		end
		
		return table.concat(ret, "<br/>")
	end
	
	local function repl(param)
		if param == "lemma" then
			return m_links.full_link({lang = lang, alt = mw.title.getCurrentTitle().text}, "term")
		elseif param == "info" then
			return data.info and " (" .. data.info .. ")" or ""
		else
			return show_form(data.forms[param])
		end
	end
	
	local collapsed_cells = [=[
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="min-width: 11em; background: var(--wikt-palette-blue-2,#ccccff);" | nominative sing.
| style="min-width: 13em;" | {{{nom_sg}}}
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | genitive sing.
| {{{gen_sg}}}
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | partitive sing.
| {{{par_sg}}}
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | partitive plur.
| {{{par_pl}}}]=]
	
	if data.n == "pl" then
		collapsed_cells = [=[
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="min-width: 11em; background: var(--wikt-palette-blue-2,#ccccff);" | nominative sing.
| style="min-width: 13em;" | {{{nom_sg}}}
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | nominative plur.
| {{{nom_pl}}}
|- class="vsShow" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | partitive plur.
| {{{par_pl}}}]=]
	end
	
	local wikicode = [=[
{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="border: solid 1px var(--wikt-palette-blue-2,#ccccff); text-align:left;" cellspacing="1" cellpadding="2"
|- style="background: var(--wikt-palette-blue-2,#ccccff); vertical-align: top;"
! class="vsToggleElement" colspan="4" | Inflection of {{{lemma}}}{{{info}}}
]=] .. collapsed_cells .. [=[

|- class="vsHide" style="background: var(--wikt-palette-blue-2,#ccccff); vertical-align: top;"
! style="min-width: 11em;" |
! style="min-width: 13em;" | singular
! style="min-width: 13em;" | plural
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | nominative
| {{{nom_sg}}}
| {{{nom_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | accusative
| {{{acc_sg}}}
| {{{acc_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | genitive
| {{{gen_sg}}}
| {{{gen_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | partitive
| {{{par_sg}}}
| {{{par_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | essive-instructive
| {{{ess_sg}}}
| {{{ess_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | translative
| {{{tra_sg}}}
| {{{tra_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | inessive
| {{{ine_sg}}}
| {{{ine_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | elative
| {{{ela_sg}}}
| {{{ela_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | illative
| {{{ill_sg}}}
| {{{ill_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | adessive
| {{{ade_sg}}}
| {{{ade_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | ablative
| {{{abl_sg}}}
| {{{abl_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | allative
| {{{all_sg}}}
| {{{all_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | abessive
| {{{abe_sg}}}
| {{{abe_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | comitative
| {{{com_sg}}}
| {{{com_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | prolative
| {{{pro_sg}}}
| {{{pro_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | approximative I
| {{{ap1_sg}}}
| {{{ap1_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | approximative II
| {{{ap2_sg}}}
| {{{ap2_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | egressive
| {{{egr_sg}}}
| {{{egr_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | terminative I
| {{{te1_sg}}}
| {{{te1_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | terminative II
| {{{te2_sg}}}
| {{{te2_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | terminative III
| {{{te3_sg}}}
| {{{te3_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-1,#E6E6FF); vertical-align:top;"
| colspan="3" |
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | additive I
| {{{ad1_sg}}}
| {{{ad1_pl}}}
|- class="vsHide" style="background: var(--wikt-palette-blue-0,#f2ffff); vertical-align: top;"
! style="background: var(--wikt-palette-blue-2,#ccccff);" | additive II
| {{{ad2_sg}}}
| {{{ad2_pl}}}
|}]=]
	return mw.ustring.gsub(wikicode, "{{{([a-z0-9_]+)}}}", repl)
end

return export