Module:ine-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 m_common = require("Module:ine-common")

local export = {}

local lang = require("Module:languages").getByCode("ine-pro")

local endings = {
	["anim"] = {
		["athem"] = {
			["nom_sg"] = {"s"},
			["voc_sg"] = {""},
			["acc_sg"] = {"m̥"},
			["gen_sg"] = {{stressed = "és", unstressed = "s"}},
			["abl_sg"] = {{stressed = "és", unstressed = "s"}},
			["dat_sg"] = {"éy"},
			["loc_sg"] = {"", "i"},
			["ins_sg"] = {{stressed = "éh₁", unstressed = "h₁"}},
			
			["nom_du"] = {"h₁(e)"},
			["voc_du"] = {"h₁(e)"},
			["acc_du"] = {"h₁(e)"},
			["gen_du"] = "?",
			["abl_du"] = "?",
			["dat_du"] = "?",
			["loc_du"] = "?",
			["ins_du"] = "?",
			
			["nom_pl"] = {"es"},
			["voc_pl"] = {"es"},
			["acc_pl"] = {"m̥s"},
			["gen_pl"] = {"óHom"},
			["abl_pl"] = {"mós"},
			["dat_pl"] = {"mós"},
			["loc_pl"] = {"sú"},
			["ins_pl"] = {"mís"},
			},
		
		["them"] = {
			["nom_sg"] = {"ós"},
			["voc_sg"] = {"é"},
			["acc_sg"] = {"óm"},
			["gen_sg"] = {"ósyo"},
			["abl_sg"] = {"éad"},
			["dat_sg"] = {"óey"},
			["loc_sg"] = {"éy", "óy"},
			["ins_sg"] = {"óh₁"},
			
			["nom_du"] = {"óh₁"},
			["voc_du"] = {"óh₁"},
			["acc_du"] = {"óh₁"},
			["gen_du"] = "?",
			["abl_du"] = "?",
			["dat_du"] = "?",
			["loc_du"] = "?",
			["ins_du"] = "?",
			
			["nom_pl"] = {"óes"},
			["voc_pl"] = {"óes"},
			["acc_pl"] = {"óms"},
			["gen_pl"] = {"óHom"},
			["abl_pl"] = {"ómos"},
			["dat_pl"] = {"ómos"},
			["loc_pl"] = {"óysu"},
			["ins_pl"] = {"ṓys"},
			},
		},
	
	["inan"] = {
		["athem"] = {
			["nom_sg"] = {""},
			["voc_sg"] = {""},
			["acc_sg"] = {""},
			
			["nom_du"] = {"ih₁"},
			["voc_du"] = {"ih₁"},
			["acc_du"] = {"ih₁"},
			
			["nom_pl"] = {"h₂"},
			["voc_pl"] = {"h₂"},
			["acc_pl"] = {"h₂"},
			},
		
		["them"] = {
			["nom_sg"] = {"óm"},
			["voc_sg"] = {"óm"},
			["acc_sg"] = {"óm"},
			
			["nom_du"] = {"óy(h₁)"},
			["voc_du"] = {"óy(h₁)"},
			["acc_du"] = {"óy(h₁)"},
			
			["nom_pl"] = {"éh₂"},
			["voc_pl"] = {"éh₂"},
			["acc_pl"] = {"éh₂"},
			},
		},
	
	["coll"] = {
		["athem"] = {
			["nom_sg"] = {"h₂"},
			["voc_sg"] = {"h₂"},
			["acc_sg"] = {"h₂"},
			},
		
		["them"] = {
			["nom_sg"] = {"éh₂"},
			["voc_sg"] = {"éh₂"},
			["acc_sg"] = {"éh₂"},
			},
		},
}

-- Copy over endings which are the same for animate and inanimate.
for _, t in ipairs({"athem", "them"}) do
	for cn, _ in pairs(endings["anim"][t]) do
		if not endings["inan"][t][cn] then
			endings["inan"][t][cn] = endings["anim"][t][cn]
		end
		
		if cn:find("_sg$") and not endings["coll"][t][cn] then
			endings["coll"][t][cn] = endings["anim"][t][cn]
		end
	end
end


local endings_pron = {
	["m"] = {
		["nom_sg"] = {"ós"},
		["acc_sg"] = {"óm"},
		["gen_sg"] = {"ósyo"},
		["abl_sg"] = {"ósmead"},
		["dat_sg"] = {"ósmey"},
		["loc_sg"] = {"ósmi"},
		["ins_sg"] = {"ónoh₁"},
		
		["nom_du"] = {"óh₁"},
		["acc_du"] = {"óh₁"},
		["gen_du"] = "?",
		["abl_du"] = "?",
		["dat_du"] = "?",
		["loc_du"] = "?",
		["ins_du"] = "?",
		
		["nom_pl"] = {"óy"},
		["acc_pl"] = {"óms"},
		["gen_pl"] = {"óysoHom"},
		["abl_pl"] = {"óymos"},
		["dat_pl"] = {"óymos"},
		["loc_pl"] = {"óysu"},
		["ins_pl"] = {"ṓys"},
		},
	
	["f"] = {
		["nom_sg"] = {"éh₂"},
		["acc_sg"] = {"éh₂m̥"},
		["gen_sg"] = {"ósyeh₂s"},
		["abl_sg"] = {"ósyeh₂s"},
		["dat_sg"] = {"ósyeh₂ey"},
		["loc_sg"] = {"ósyeh₂"},
		["ins_sg"] = {"éh₂(e)h₁"},
		
		["nom_du"] = "?",
		["acc_du"] = "?",
		["gen_du"] = "?",
		["abl_du"] = "?",
		["dat_du"] = "?",
		["loc_du"] = "?",
		["ins_du"] = "?",
		
		["nom_pl"] = {"éh₂es"},
		["acc_pl"] = {"éh₂m̥s"},
		["gen_pl"] = {"éh₂soHom"},
		["abl_pl"] = {"éh₂mos"},
		["dat_pl"] = {"éh₂mos"},
		["loc_pl"] = {"éh₂su"},
		["ins_pl"] = {"éh₂mis"},
		},
	
	["n"] = {
		["nom_sg"] = {"ód"},
		["acc_sg"] = {"ód"},
		
		["nom_du"] = {"óy"},
		["acc_du"] = {"óy"},
		
		["nom_pl"] = {"éh₂"},
		["acc_pl"] = {"éh₂"},
		},
}

-- Copy over endings which are the same for animate and inanimate.
for cn, _ in pairs(endings_pron["m"]) do
	if not endings_pron["n"][cn] then
		endings_pron["n"][cn] = endings_pron["m"][cn]
	end
end


local function inflect(data, prefix, endings, stem1, stem2, loc_sg_stem)
	stem2 = stem2 or stem1
	
	-- Is the stem thematic?
	local thematic_unstressed = false
	
	if mw.ustring.find(stem1, "[eoéó]$") then
		endings = mw.clone(endings.them or endings)
		
		if mw.ustring.find(stem1, "[eo]$") then
			thematic_unstressed = true
		end
		
		stem1 = mw.ustring.gsub(stem1, "[eoéó]$", "")
		stem2 = stem1
	else
		endings = endings.athem or endings
		
		if mw.ustring.find(stem1, "[eoéó]h₂$") and stem1 == stem2 then
			thematic_unstressed = true
		end
	end
	
	if not loc_sg_stem then
		if mw.ustring.find(stem2, "[áéíĺḿńóŕúḗṓ́]") then
			loc_sg_stem = stem2
		else
			loc_sg_stem = stem1
		end
	end
	
	local stem2_zero = stem2
	
	if mw.ustring.find(stem1, "[iu]$") then
		stem2_zero = mw.ustring.gsub(stem2, "é[wy]$", {["éw"] = "ú", ["éy"] = "í"})
	end
	
	local stem1_full = stem1
	
	if stem1 ~= stem2 and mw.ustring.gsub(stem1, "os$", "es") == stem2 then
		stem1_full = stem2
	end
	
	local nom_pl_stem = mw.ustring.gsub(stem1, "[íiu]$", {["í"] = "éy", ["i"] = "ey", ["u"] = "ew"})
	
	-- Go over each case-number combination
	for cn, cnendings in pairs(endings) do
		if cnendings == "?" then
			data.forms[(prefix and prefix .. "_" or "") .. cn] = {"?"}
		elseif cnendings then
			data.forms[(prefix and prefix .. "_" or "") .. cn] = {}
			
			for _, cnending in ipairs(cnendings) do
				local stem = stem1
				
				-- Use stem2 if the ending can be stressed, stem1 otherwise
				if cn == "loc_sg" then
					stem = loc_sg_stem
				elseif cn == "ins_sg" or cn == "abl_pl" or cn == "dat_pl" or cn == "loc_pl" or cn == "ins_pl" then
					stem = stem2_zero
				elseif (cn == "nom_du" or cn == "voc_du" or cn == "acc_du") then
					stem = stem1_full
				elseif (cn == "nom_pl" or cn == "voc_pl") and cnending == "es" then
					stem = nom_pl_stem
				elseif cnending.stressed or mw.ustring.find(cnending, "[áéíĺḿńóŕúḗṓ́]") then
					stem = stem2
				end
				
				local ending = (thematic_unstressed and (cnending.unstressed or m_common.destress(cnending))) or cnending.stressed or cnending
				local ending_unstr = cnending.unstressed
				
				if (cn == "gen_sg" or cn == "abl_sg") and ending_unstr == "s" and mw.ustring.find(stem, "s$") then
					ending_unstr = "os"
				end
				
				if mw.ustring.find(stem, "[iu]$") then
					if cn == "acc_sg" and ending == "m̥" then
						ending = "m"
					elseif cn == "acc_pl" and ending == "m̥s" then
						ending = "ms"
					end
				end
				
				if mw.ustring.find(stem, "[eéoóaáiíuú]h₂$") and cn == "nom_sg" and ending == "s" then
					ending = ""
				end
				
				if not (cnending == "i" and mw.ustring.find(stem, "i$")) then
					table.insert(data.forms[(prefix and prefix .. "_" or "") .. cn], m_common.add_ending(stem, ending, ending_unstr, cn == "nom_sg" and ending == "s"))
				end
			end
		end
	end
end

local function postprocess(data)
	for key, form in pairs(data.forms) do
		-- Do not show singular, dual or plural forms for nouns that don't have them
		if (not data.sg and key:find("_sg$")) or (not data.du and key:find("_du$")) or (not data.pl and key:find("_pl$")) or (not data.coll and key:find("_coll$")) then
			form = nil
		end
		
		data.forms[key] = form
	end
end

function export.masc(frame)
	local params = {
		[1] = {required = true},
		[2] = {},
		["nom_sg"] = {},
		["loc_sg"] = {},
		
		["coll"] = {},
		["coll2"] = {},
		["coll_loc"] = {},
		
		["ac"] = {},
		["n"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or "h₂éǵro"
	end
	
	args[2] = args[2] or args[1]
	
	local data = {forms = {}, title = nil, categories = {}}
	data.sg = true
	data.du = true
	data.pl = true
	data.coll = false
	data.voc = true
	
	if args["n"] then
		if not mw.ustring.find(args["n"], "s") then
			data.sg = false
		end
		
		if not mw.ustring.find(args["n"], "d") then
			data.du = false
		end
		
		if not mw.ustring.find(args["n"], "p") then
			data.pl = false
		end
	end
	
	local stem_type = {}
	
	if mw.ustring.find(args[1], "[eoéó]$") then
		data.info = "Thematic"
		
		table.insert(data.categories, lang:getCanonicalName() .. " thematic o-stem nouns")
	elseif mw.ustring.find(args[1], "[eoéó]h₂$") and args[1] == args[2] then
		data.info = "Thematic in " .. m_links.full_link({lang = lang, alt = "*-eh₂"}, "term")
		table.insert(data.categories, lang:getCanonicalName() .. " thematic eh₂-stem nouns")
	else
		data.info = "Athematic"
		
		if mw.ustring.find(args[1], "ti$") then
			stem_type = " ti-stem"
		elseif mw.ustring.find(args[1], "tu$") then
			stem_type = " tu-stem"
		elseif mw.ustring.find(args[1], "i$") then
			stem_type = " i-stem"
		elseif mw.ustring.find(args[1], "ih₂$") then
			stem_type = " ih₂-stem"
		elseif mw.ustring.find(args[1], "u$") then
			stem_type = " u-stem"
		elseif mw.ustring.find(args[1], "uh₂$") then
			stem_type = " uh₂-stem"
		elseif mw.ustring.find(args[1], "[eéoóaáiíuú][%a₁₂₃]+[eéoó]m$") then
			stem_type = " m-stem"
		elseif mw.ustring.find(args[1], "[eéoóaáiíuú][%a₁₂₃]+m[eéoó]n$") then
			stem_type = " men-stem"
		elseif mw.ustring.find(args[1], "[eéoóaáiíuú][%a₁₂₃]+[eéoó]n$") then
			stem_type = " n-stem"
		elseif mw.ustring.find(args[1], "[eéoóaáiíuú][%a₁₂₃]+[eéoó][lr]$") then
			stem_type = " r-stem"
		else
			stem_type = " root"
		end
		
		if args["ac"] then
			data.info = data.info .. ", " .. args["ac"]
			table.insert(data.categories, lang:getCanonicalName() .. " " .. args["ac"] .. stem_type .." nouns")
		else
			table.insert(data.categories, lang:getCanonicalName() .. " athematic nouns")
		end
	end
	
	-- Create the forms
	inflect(data, nil, endings["anim"], args[1], args[2], args["loc_sg"])
	
	if args["nom_sg"] then
		data.forms["nom_sg"] = {args["nom_sg"]}
	end
	
	-- Collective
	if args["coll"] then
		args["coll2"] = args["coll2"] or args["coll"]
		data.coll = true
		
		local tempdata = {forms = {}}
		
		inflect(tempdata, nil, endings["coll"], args["coll"], args["coll2"], args["coll_loc"])
		
		for cn, forms in pairs(tempdata.forms) do
			if cn:find("_sg$") then
				local coll = cn:gsub("_sg$", "_coll")
				data.forms[coll] = forms
			end
		end
	end
	
	postprocess(data)
	
	return make_table(data)
end

function export.neut(frame)
	local params = {
		[1] = {required = true},
		[2] = {},
		["loc_sg"] = {},
		
		["coll"] = {},
		["coll2"] = {},
		["coll_loc"] = {},
		
		["ac"] = {},
		["n"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or "wérǵo"
	end
	
	args[2] = args[2] or args[1]
	
	local data = {forms = {}, title = nil, categories = {}}
	data.sg = true
	data.du = true
	data.pl = true
	data.coll = false
	data.voc = true
	
	if args["n"] then
		if not mw.ustring.find(args["n"], "s") then
			data.sg = false
		end
		
		if not mw.ustring.find(args["n"], "d") then
			data.du = false
		end
		
		if not mw.ustring.find(args["n"], "p") then
			data.pl = false
		end
	end
	
	local stem_type = {}
	
	if mw.ustring.find(args[1], "[eoéó]$") then
		data.info = "Thematic"
		table.insert(data.categories, lang:getCanonicalName() .. " thematic neuter o-stem nouns")
	else
		data.info = "Athematic"
		
		if mw.ustring.find(args[1], "i$") then
			stem_type = " i-stem"
		elseif mw.ustring.find(args[1], "u$") then
			stem_type = " u-stem"
		elseif mw.ustring.find(args[1], "mn̥$") then
			stem_type = " men-stem"
		elseif mw.ustring.find(args[1], "[lr]̥$") then
			stem_type = " r/n-stem"
		elseif mw.ustring.find(args[1], "os$") then
			stem_type = " s-stem"
		else
			stem_type = " root"
		end
		
		if args["ac"] then
			data.info = data.info .. ", " .. args["ac"]
			table.insert(data.categories, lang:getCanonicalName() .. " " .. args["ac"] .. " neuter".. stem_type .. " nouns")
		else
			table.insert(data.categories, lang:getCanonicalName() .. " athematic nouns")
		end
	end
	
	-- Create the forms
	inflect(data, nil, endings["inan"], args[1], args[2], args["loc_sg"])
	
	-- Collective
	if args["coll"] then
		args["coll2"] = args["coll2"] or args["coll"]
		data.coll = true
		
		local tempdata = {forms = {}}
		
		inflect(tempdata, nil, endings["coll"], args["coll"], args["coll2"], args["coll_loc"])
		
		for cn, forms in pairs(tempdata.forms) do
			if cn:find("_sg$") then
				local coll = cn:gsub("_sg$", "_coll")
				data.forms[coll] = forms
			end
		end
	end
	
	postprocess(data)
	
	return make_table(data)
end

function export.adj(frame)
	local params = {
		[1] = {required = true},
		[2] = {},
		["loc_sg"] = {},
		
		[3] = {},
		[4] = {},
		
		["ac"] = {},
		["n"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or "néwo"
	end
	
	args[2] = args[2] or args[1]
	
	local data = {forms = {}, title = nil, categories = {}}
	data.genders = true
	data.sg = true
	data.du = true
	data.pl = true
	data.voc = true
	
	if args["n"] then
		if not mw.ustring.find(args["n"], "s") then
			data.sg = false
		end
		
		if not mw.ustring.find(args["n"], "d") then
			data.du = false
		end
		
		if not mw.ustring.find(args["n"], "p") then
			data.pl = false
		end
	end
	
	if mw.ustring.find(args[1], "[eoéó]$") then
		data.info = "Thematic"
		table.insert(data.categories, lang:getCanonicalName() .. " thematic adjectives")
		
		if not args[3] then
			args[3] = mw.ustring.gsub(args[1], "[eoéó]$", {["e"] = "eh₂", ["o"] = "eh₂", ["é"] = "éh₂", ["ó"] = "éh₂"})
			args[4] = args[3]
		end
	else
		data.info = "Athematic"
		
		if args["ac"] then
			data.info = data.info .. ", " .. args["ac"]
			table.insert(data.categories, lang:getCanonicalName() .. " " .. args["ac"] .. " adjectives")
		else
			table.insert(data.categories, lang:getCanonicalName() .. " athematic adjectives")
		end
	end
	
	-- Create the forms
	inflect(data, "m", endings["anim"], args[1], args[2], args["loc_sg"])
	inflect(data, "f", endings["anim"], args[3], args[4])
	inflect(data, "n", endings["inan"], args[1], args[2], args["loc_sg"])
	
	postprocess(data)
	
	return make_table(data)
end

function export.pron_adj(frame)
	local params = {
		[1] = {required = true},
		
		["m_nom_sg"] = {},
		["f_nom_sg"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or "h₂élyo"
	end
	
	local data = {forms = {}, title = nil, categories = {}}
	data.genders = true
	data.sg = true
	data.du = true
	data.pl = true
	data.voc = false
	
	if mw.ustring.find(args[1], "[eoéó]$") then
		data.info = "Thematic pronominal"
	else
		error("Thematic only for now.")
	end
	
	-- Create the forms
	inflect(data, "m", endings_pron["m"], args[1])
	inflect(data, "f", endings_pron["f"], args[1])
	inflect(data, "n", endings_pron["n"], args[1])
	
	data.forms["m_nom_sg"] = args["m_nom_sg"] and {args["m_nom_sg"]} or data.forms["m_nom_sg"]
	data.forms["f_nom_sg"] = args["f_nom_sg"] and {args["f_nom_sg"]} or data.forms["f_nom_sg"]
	
	postprocess(data)
	
	return make_table(data)
end


local names = {
	["nom"] = "nominative",
	["voc"] = "vocative",
	["acc"] = "accusative",
	["gen"] = "genitive",
	["abl"] = "ablative",
	["dat"] = "dative",
	["loc"] = "locative",
	["ins"] = "instrumental",
	
	["sg"] = "singular",
	["du"] = "dual",
	["pl"] = "plural",
	["coll"] = "collective",
	
	["m"] = "masculine",
	["f"] = "feminine",
	["n"] = "neuter",
}

-- Make the table
function make_table(data)
	local function repl(param)
		if param == "info" then
			return mw.getContentLanguage():ucfirst(data.info or "")
		end
		
		local form = data.forms[param]
		
		if not form or #form == 0 then
			return "—"
		end
		
		local ret = {}
		
		for key, subform in ipairs(form) do
			table.insert(ret, m_links.full_link({lang = lang, alt = "*" .. subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local numbers = {"sg", "du", "pl"}
	local genders = {"x"}
	local cases = {"nom", "acc", "gen", "abl", "dat", "loc", "ins"}
	
	if data.voc then
		table.insert(cases, 2, "voc")
	end
	
	if data.genders then
		genders = {"m", "f", "n"}
	elseif data.coll then
		table.insert(numbers, "coll")
	end
	
	local first_number = "sg"
	
	if not data.sg then
		first_number = "du"
		
		if not data.du then
			first_number = "pl"
		end
	end
	
	local wikicode = {}
	
	table.insert(wikicode, "{| class=\"inflection-table vsSwitcher\" data-toggle-category=\"inflection\" style=\"background: #FAFAFA; border: 1px solid #d0d0d0; text-align: left;\" cellspacing=\"1\" cellpadding=\"2\"")
	table.insert(wikicode, "|- style=\"background: #CCCCFF;\"\n! class=\"vsToggleElement\" colspan=\"" .. (#numbers + 1) .. "\" | {{{info}}}")
	
	table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #CCCCFF;\"")
	table.insert(wikicode, "!")
	
	if data.genders then
		table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names["m"])
		table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names["f"])
	else
		table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names[first_number])
		
		if data.coll then
			table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names["coll"])
		end
	end
	
	table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #F2F2FF;\"")
	table.insert(wikicode, "! style=\"min-width: 8em; background: #E6E6FF;\" | " .. names["nom"])
	
	if data.genders then
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{m_nom_" .. first_number .. "}}}")
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{f_nom_" .. first_number .. "}}}")
	else
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{nom_" .. first_number .. "}}}")
		
		if data.coll then
			table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{nom_coll}}}")
		end
	end
	
	table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #F2F2FF;\"")
	table.insert(wikicode, "! style=\"min-width: 8em; background: #E6E6FF;\" | " .. names["gen"])
	
	if data.genders then
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{m_gen_" .. first_number .. "}}}")
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{f_gen_" .. first_number .. "}}}")
	else
		table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{gen_" .. first_number .. "}}}")
		
		if data.coll then
			table.insert(wikicode, "| style=\"min-width: 11em;\" | {{{gen_coll}}}")
		end
	end
	
	for _, gender in ipairs(genders) do
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background: #CCCCFF;\"")
		
		if data.genders then
			table.insert(wikicode, "! " .. names[gender])
		else
			table.insert(wikicode, "!")
		end
		
		for _, number in ipairs(numbers) do
			table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names[number])
		end
		
		for _, case in ipairs(cases) do
			table.insert(wikicode, "|- class=\"vsHide\" style=\"background-color: #F2F2FF;\"\n! style=\"min-width: 8em; background-color: #E6E6FF;\" | " .. names[case])
			
			for _, number in ipairs(numbers) do
				if data.genders then
					table.insert(wikicode, "| {{{" .. gender .. "_" .. case .. "_" .. number .. "}}}")
				else
					table.insert(wikicode, "| {{{" .. case .. "_" .. number .. "}}}")
				end
			end
		end
	end
	
	table.insert(wikicode, [=[|}]=])
	
	wikicode = table.concat(wikicode, "\n")
	
	return (mw.ustring.gsub(wikicode, "{{{([a-z0-9_]+)}}}", repl)) .. m_utilities.format_categories(data.categories, lang)
end

return export