Module:zu-nouns

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:zu-common")

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

local export = {}


local prefixes = {
	["1"] = {
		"^([uU][" .. m_common.diacritic .. "]*[mM][uU][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*[mM][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*)([nN].+)$",
		},
	["1a"] = {
		"^([uU][" .. m_common.diacritic .. "]*)(.+)$",
		},
	["2"] = {
		"^([aA][" .. m_common.diacritic .. "]*[bB][aeAE][" .. m_common.diacritic .. "]*)(.+)$",
		"^([aA][" .. m_common.diacritic .. "]*[bB])([" .. m_common.vowel .. ".+)$",
		},
	["2a"] = {
		"^([oO][" .. m_common.diacritic .. "]*)(.+)$",
		},
	["3"] = {
		"^([uU][" .. m_common.diacritic .. "]*[mM][uU][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*[mM][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*)([nN].+)$",
		},
	["4"] = {
		"^([iI][" .. m_common.diacritic .. "]*[mM][iI][" .. m_common.diacritic .. "]*)(.+)$",
		"^([iI][" .. m_common.diacritic .. "]*[mM])([" .. m_common.vowel .. "].+)$",
		},
	["5"] = {
		"^([iI][" .. m_common.diacritic .. "]*)(.+)$",
		},
	["6"] = {
		"^([aA][" .. m_common.diacritic .. "]*[mM][aA][" .. m_common.diacritic .. "]*)(.+)$",
		"^([aA][" .. m_common.diacritic .. "]*[mM])([" .. m_common.vowel .. "].+)$",
		},
	["7"] = {
		"^([iI][" .. m_common.diacritic .. "]*[sS][iI][" .. m_common.diacritic .. "]*)(.+)$",
		"^([iI][" .. m_common.diacritic .. "]*[sS])([" .. m_common.vowel .. "].+)$",
		},
	["8"] = {
		"^([iI][" .. m_common.diacritic .. "]*[zZ][iI][" .. m_common.diacritic .. "]*)(.+)$",
		"^([iI][" .. m_common.diacritic .. "]*[zZ])([" .. m_common.vowel .. "].+)$",
		},
	["9"] = {
		"^([iI][" .. m_common.diacritic .. "]*[mMnN])([^" .. m_common.vowel .. "].+)$",
		"^([iI][" .. m_common.diacritic .. "]*)([lLmMnN][" .. m_common.vowel .. "].+)$",
		},
	["10"] = {
		"^([iI][" .. m_common.diacritic .. "]*[zZ][iI][" .. m_common.diacritic .. "]*[mMnN])([^" .. m_common.vowel .. "].+)$",
		"^([iI][" .. m_common.diacritic .. "]*[zZ][iI][" .. m_common.diacritic .. "]*)([hHlLmMnN][" .. m_common.vowel .. "wW].+)$",
		},
	["11"] = {
		"^([uU][" .. m_common.diacritic .. "]*)(.+)$",
		--"^([uU][" .. m_common.diacritic .. "]*[lL][uU][" .. m_common.diacritic .. "]*)(.+)$",
		--"^([uU][" .. m_common.diacritic .. "]*[lL][wW])([" .. m_common.vowel .. "].+)$",
		},
	["14"] = {
		"^([uU][" .. m_common.diacritic .. "]*[bB][uU][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*[bB])([" .. m_common.vowel .. "].+)$",
		"^([uU][" .. m_common.diacritic .. "]*[tT][sS][hH][wW]?)([aA].+)$",
		},
	["15"] = {
		"^([uU][" .. m_common.diacritic .. "]*[kK][uU][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*[kK][wW])([" .. m_common.vowel .. "].+)$",
		},
	["17"] = {
		"^([uU][" .. m_common.diacritic .. "]*[kK][uU][" .. m_common.diacritic .. "]*)(.+)$",
		"^([uU][" .. m_common.diacritic .. "]*[kK][wW])([" .. m_common.vowel .. "].+)$",
		},
}


local function split_prefix(word, class, tone)
	if not prefixes[class] then
		error("Invalid class \"" .. class .. "\".")
	end

	local prefix, stem
	word = mw.ustring.toNFD(word)
	
	for _, pattern in ipairs(prefixes[class]) do
		prefix, stem = mw.ustring.match(word, pattern)
		
		if prefix then
			break
		end
	end
	
	if not prefix then
		if mw.title.getCurrentTitle().nsText ~= "Template" then
			error("Word \"" .. word .. "\" does not match any valid prefix of class \"" .. class .. "\".")
		end
	else
		local sstem = m_common.split_syllables(stem)
		local stone = mw.text.split(tone or mw.ustring.rep("L", #sstem), "")
		
		if #sstem ~= #stone then
			error("The word \"" .. stem .. "\" and the tone pattern " .. tone .. " have different numbers of syllables.")
		end
		
		return mw.ustring.toNFC(prefix), mw.ustring.toNFC(stem)
	end
end


function makeSortKey(word, class)
	local prefix, stem = split_prefix(word, class)
	
	return (lang:makeSortKey(stem or word))
end


local function simple(data, base, prefix, class)
	base = (lang:makeEntryName(base))
	
	if prefix then
		prefix = prefix .. "_"
	else
		prefix = ""
	end
	
	if class == "2a" then
		data.forms[prefix .. "simp"] = {"b" .. base}
	elseif class == "5" then
		data.forms[prefix .. "simp"] = {(mw.ustring.gsub(base, "^i", "li"))}
	elseif class == "11" then
		data.forms[prefix .. "simp"] = {(mw.ustring.gsub(base, "^u", "lu"))}
	else
		data.forms[prefix .. "simp"] = {(mw.ustring.gsub(base, "^[aiu]%-?", ""))}
	end
end


local function locative_ku(data, base, prefix, tone)
	base = (lang:makeEntryName(base))
	
	if prefix then
		prefix = prefix .. "_"
	else
		prefix = ""
	end
	
	if mw.ustring.find(base, "^[au]") then
		data.forms[prefix .. "loc"]  = {m_common.apply_tone("ku" .. mw.ustring.gsub(base, "^[au]", ""), tone)}
	elseif mw.ustring.find(base, "^[" .. m_common.vowel .. "]") then
		data.forms[prefix .. "loc"]  = {m_common.apply_tone("k" .. base)}
	elseif base == "mi" or base == "thi" or base == "ni" then
		data.forms[prefix .. "loc"] = {m_common.apply_tone("ki" .. base, tone)}
	else
		data.forms[prefix .. "loc"]  = {m_common.apply_tone("ku" .. base, tone)}
	end
end


local function locative_e(data, base, prefix, class)
	base = (lang:makeEntryName(base))
	
	if prefix then
		prefix = prefix .. "_"
	else
		prefix = ""
	end
	
	if mw.ustring.find(base, "^u") and class == "11" then
		base = mw.ustring.gsub(base, "^u", "o")
	else
		base = mw.ustring.gsub(base, "^[aiu]", "e")
	end
	
	data.forms[prefix .. "loc"]  = {base}
end


local function locative_extend(base)
	base = (lang:makeEntryName(base))
	
	base = mw.ustring.gsub(base, "[aou]$", {["a"] = "e", ["o"] = "we", ["u"] = "wi"}) .. "ni"
	
	base = mw.ustring.gsub(base, "mbw([ei]ni)$", "nj%1")
	base = mw.ustring.gsub(base, "mpw([ei]ni)$", "ntsh%1")
	base = mw.ustring.gsub(base, "bhw([ei]ni)$", "j%1")
	base = mw.ustring.gsub(base, "[bp]w([ei]ni)$", "tsh%1")
	base = mw.ustring.gsub(base, "phw([ei]ni)$", "sh%1")
	base = mw.ustring.gsub(base, "mw([ei]ni)$", "ny%1")
	base = mw.ustring.gsub(base, "([fvw])w([ei]ni)$", "%1%2")
	
	return base
end


local function copulative(data, base, prefix, class, tone)
	base = (lang:makeEntryName(base))
	
	if prefix then
		prefix = prefix .. "_"
	else
		prefix = ""
	end
	
	if mw.ustring.find(base, "^u") and class == "11" then
		data.forms[prefix .. "cop"]  = {m_common.apply_tone("w" .. base)}
	elseif mw.ustring.find(base, "^[aou]") then
		data.forms[prefix .. "cop"]  = {m_common.apply_tone("ng" .. base)}
	elseif mw.ustring.find(base, "^i") then
		data.forms[prefix .. "cop"]  = {m_common.apply_tone("y" .. base)}
	elseif base == "we" or base == "ye" then
		data.forms[prefix .. "cop"] = {m_common.apply_tone("ngu" .. base, tone)}
	else
		data.forms[prefix .. "cop"]  = {m_common.apply_tone("yi" .. base, tone)}
	end
end


local function possessive(data, base, prefix, ka, tone)
	base = (lang:makeEntryName(base))
	
	local tone_subst
	if tone then
		tone_subst = "H" .. tone
	end
	
	if prefix then
		prefix = prefix .. "_"
	else
		prefix = ""
	end
	
	if ka then
		base = mw.ustring.gsub(base, "^u", "")
		
		data.forms[prefix .. "poss_mod_c1" ] = {  "ka" .. base}
		data.forms[prefix .. "poss_mod_c2" ] = {"baka" .. base}
		data.forms[prefix .. "poss_mod_c3" ] = {  "ka" .. base}
		data.forms[prefix .. "poss_mod_c4" ] = {  "ka" .. base}
		data.forms[prefix .. "poss_mod_c5" ] = {"lika" .. base}
		data.forms[prefix .. "poss_mod_c6" ] = {  "ka" .. base}
		data.forms[prefix .. "poss_mod_c7" ] = {"sika" .. base}
		data.forms[prefix .. "poss_mod_c8" ] = {"zika" .. base}
		data.forms[prefix .. "poss_mod_c9" ] = {  "ka" .. base}
		data.forms[prefix .. "poss_mod_c10"] = {"zika" .. base}
		data.forms[prefix .. "poss_mod_c11"] = {"luka" .. base}
		data.forms[prefix .. "poss_mod_c14"] = {"buka" .. base}
		data.forms[prefix .. "poss_mod_c15"] = {"kuka" .. base}
		data.forms[prefix .. "poss_mod_c17"] = {"kuka" .. base}
		
		data.forms[prefix .. "poss_subst_c1" ] = {  "oka" .. base}
		data.forms[prefix .. "poss_subst_c2" ] = {"abaka" .. base}
		data.forms[prefix .. "poss_subst_c3" ] = {  "oka" .. base}
		data.forms[prefix .. "poss_subst_c4" ] = {  "eka" .. base}
		data.forms[prefix .. "poss_subst_c5" ] = {"elika" .. base}
		data.forms[prefix .. "poss_subst_c6" ] = {  "aka" .. base}
		data.forms[prefix .. "poss_subst_c7" ] = {"esika" .. base}
		data.forms[prefix .. "poss_subst_c8" ] = {"ezika" .. base}
		data.forms[prefix .. "poss_subst_c9" ] = {  "eka" .. base}
		data.forms[prefix .. "poss_subst_c10"] = {"ezika" .. base}
		data.forms[prefix .. "poss_subst_c11"] = {"oluka" .. base}
		data.forms[prefix .. "poss_subst_c14"] = {"obuka" .. base}
		data.forms[prefix .. "poss_subst_c15"] = {"okuka" .. base}
		data.forms[prefix .. "poss_subst_c17"] = {"okuka" .. base}
	else
		local w
		if mw.ustring.find(base, "^[ou]") then
			base = mw.ustring.gsub(base, "^u", "o")
			w = ""
		elseif mw.ustring.find(base, "^[ai]") then
			base = mw.ustring.gsub(base, "^i", "e")
			w = "w"
		else
			base = "a" .. base
			w = "w"
		end
		
		data.forms[prefix .. "poss_mod_c1" ] = {m_common.apply_tone("w" .. base, tone)}
		data.forms[prefix .. "poss_mod_c2" ] = {m_common.apply_tone("b" .. base, tone)}
		data.forms[prefix .. "poss_mod_c3" ] = {m_common.apply_tone("w" .. base, tone)}
		data.forms[prefix .. "poss_mod_c4" ] = {m_common.apply_tone("y" .. base, tone)}
		data.forms[prefix .. "poss_mod_c5" ] = {m_common.apply_tone("l" .. base, tone)}
		data.forms[prefix .. "poss_mod_c6" ] = {m_common.apply_tone(base, tone)}
		data.forms[prefix .. "poss_mod_c7" ] = {m_common.apply_tone("s" .. base, tone)}
		data.forms[prefix .. "poss_mod_c8" ] = {m_common.apply_tone("z" .. base, tone)}
		data.forms[prefix .. "poss_mod_c9" ] = {m_common.apply_tone("y" .. base, tone)}
		data.forms[prefix .. "poss_mod_c10"] = {m_common.apply_tone("z" .. base, tone)}
		data.forms[prefix .. "poss_mod_c11"] = {m_common.apply_tone("l" .. w .. base, tone)}
		data.forms[prefix .. "poss_mod_c14"] = {m_common.apply_tone("b" .. base, tone)}
		data.forms[prefix .. "poss_mod_c15"] = {m_common.apply_tone("k" .. w .. base, tone)}
		data.forms[prefix .. "poss_mod_c17"] = {m_common.apply_tone("k" .. w .. base, tone)}
		
		data.forms[prefix .. "poss_subst_c1" ] = {m_common.apply_tone("ow" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c2" ] = {m_common.apply_tone("ab" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c3" ] = {m_common.apply_tone("ow" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c4" ] = {m_common.apply_tone("ey" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c5" ] = {m_common.apply_tone("el" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c6" ] = {m_common.apply_tone("aw" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c7" ] = {m_common.apply_tone("es" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c8" ] = {m_common.apply_tone("ez" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c9" ] = {m_common.apply_tone("ey" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c10"] = {m_common.apply_tone("ez" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c11"] = {m_common.apply_tone("ol" .. w .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c14"] = {m_common.apply_tone("ob" .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c15"] = {m_common.apply_tone("ok" .. w .. base, tone_subst)}
		data.forms[prefix .. "poss_subst_c17"] = {m_common.apply_tone("ok" .. w .. base, tone_subst)}
	end
end


local function forms(data, n, class, base, shortloc, loc)
	-- Full form
	data.forms[n .. "_full"] = {base}
	
	-- Simple form
	simple(data, base, n, class)
	
	-- Locative
	if class == "1" or class == "1a" or class == "2" or class == "2a" then
		locative_ku(data, base, n)
	elseif shortloc then
		locative_e(data, base, n, class)
	elseif loc then
		data.forms[n .. "_loc"]  = {loc}
	else
		local loc = locative_extend(base)
		locative_e(data, loc, n, class)
	end
	
	-- Copulative
	copulative(data, base, n, class)
	
	-- Possessive forms
	possessive(data, base, n, class == "1a")
end


function export.noun(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "L" or nil},
		[2] = {required = true, default = "1"},
		[3] = {default = mw.title.getCurrentTitle().nsText == "Template" and "2" or nil},
		[4] = {default = mw.title.getCurrentTitle().nsText == "Template" and "abantu" or nil},
		
		["shortloc"] = {type = "boolean"},
		["loc_sg"] = {default = false},
		["loc_pl"] = {default = false}
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {forms = {}, info = "", categories = {lang:getCanonicalName() .. " class " .. args[2] .. " nouns"}}
	
	if args[1] then
		table.insert(data.categories, lang:getCanonicalName() .. " nouns with tone " .. args[1])
	else
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " noun entries")
	end
	
	
	data.info = "class " .. args[2] .. (args[3] and "/" .. args[3] or "")
	
	if args[2] == "2" or args[2] == "2a" or args[2] == "4" or args[2] == "6" or args[2] == "8" or args[2] == "10" then
		if args[3] or args[4] then
			error("Nouns of plural classes cannot have plural forms.")
		end
		
		forms(data, "pl", args[2], mw.title.getCurrentTitle().subpageText, args["shortloc"], args["loc_pl"])
		table.insert(data.categories, lang:getCanonicalName() .. " pluralia tantum")
	else
		forms(data, "sg", args[2], mw.title.getCurrentTitle().subpageText, args["shortloc"], args["loc_sg"])
		
		-- Plural
		if args[3] then
			forms(data, "pl", args[3], args[4], args["shortloc"], args["loc_pl"])
		else
			table.insert(data.categories, lang:getCanonicalName() .. " singularia tantum")
		end
	end
	
	if args["shortloc"] then
		data.info = data.info .. ", short locative"
		table.insert(data.categories, lang:getCanonicalName() .. " nouns with short locative")
	end
	
	return make_table(data) .. m_utilities.format_categories(data.categories, lang, (makeSortKey(mw.title.getCurrentTitle().subpageText, args[2])))
end


function export.pron(frame)
	local params = {
		[1] = {},
		[2] = {},
		[3] = {},
		[4] = {},
		[5] = {},
		
		["head"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {forms = {}, info = "", categories = {}}
	data.pron = true
	if args[1] then
		table.insert(data.categories, lang:getCanonicalName() .. " pronouns with tone " .. args[1])
	else
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " pronoun entries")
	end
	
	local base  = m_common.apply_tone(args["head"] or mw.title.getCurrentTitle().subpageText, args[1])
	local stem  = args[2] and m_common.apply_tone(args[2], args[3]) or base
	local pstem = args[4] and m_common.apply_tone(args[4], args[5]) or stem
	
	data.info = "stem " .. m_links.full_link({lang = lang, alt = "-" .. stem}, "term")
	
	if args[4] then
		data.info = data.info .. ", poss. stem " .. m_links.full_link({lang = lang, alt = "-" .. pstem}, "term")
	end
	
	data.forms["full"] = {base}

	if args[3] then
		locative_ku(data, stem, nil, "H" .. args[3])
		copulative(data, stem, nil, nil, "H" .. args[3])
	else
		locative_ku(data, stem)
		copulative(data, stem)
	end
		
	if stem == "mi" or stem == "we" then
		possessive(data, pstem, nil, nil, "HL")
	elseif pstem == "ithu" or stem == "inu" then
		possessive(data, pstem, nil, nil, "FL")
	else
		if args[5] then
			possessive(data, pstem, nil, nil, "FL")
		else
			possessive(data, pstem)
		end
	end
	
	return make_table(data) .. m_utilities.format_categories(data.categories, lang)
end


-- 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, term = subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local names = {
		["full"] = "full form",
		["simp"] = "simple form",
		["loc"]  = "locative",
		["cop"]  = "copulative",
		
		["sg"] = "singular",
		["pl"] = "plural",
		
		["mod"] = "modifier",
		["subst"] = "substantive",
		
		["c1"] = "class 1",
		["c2"] = "class 2",
		["c3"] = "class 3",
		["c4"] = "class 4",
		["c5"] = "class 5",
		["c6"] = "class 6",
		["c7"] = "class 7",
		["c8"] = "class 8",
		["c9"] = "class 9",
		["c10"] = "class 10",
		["c11"] = "class 11",
		["c14"] = "class 14",
		["c15"] = "class 15",
		["c17"] = "class 17",
	}
	
	local columns = {"mod", "subst"}
	local numbers = {"sg", "pl"}
	local cases = {"full", "simp", "loc", "cop"}
	local classes = {"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c14", "c15", "c17"}
	
	if data.pron then
		numbers = {""}
		cases = {"full", "loc", "cop"}
	end
	
	local wikicode = {}
	
	table.insert(wikicode, "{| class=\"wikitable inflection-table vsSwitcher\" data-toggle-category=\"inflection\" style=\"border-style: double; border-width: 3px; margin: 0;\"")
	table.insert(wikicode, "|-")
	table.insert(wikicode, "! class=\"vsToggleElement\" style=\"background: #CCC; text-align: left;\" colspan=\"" .. tostring(#numbers * #columns + 1) .. "\" | {{{info}}}")
	
	if not data.pron then
		table.insert(wikicode, "|- class=\"vsShow\"")
		table.insert(wikicode, "|")
		
		for _, number in ipairs(numbers) do
			table.insert(wikicode, "! " .. mw.getContentLanguage():ucfirst(names[number]))
		end
	end
	
	for _, case in ipairs({"full", "loc"}) do
		table.insert(wikicode, "|- class=\"vsShow\"")
		table.insert(wikicode, "! style=\"min-width: 8em;\" | " .. mw.getContentLanguage():ucfirst(names[case]))
		
		if data.pron then
			table.insert(wikicode, "| style=\"min-width: 10em;\" | {{{" .. case .. "}}}")
		else
			for _, number in ipairs(numbers) do
				table.insert(wikicode, "| style=\"min-width: 10em;\" | {{{" .. number .. "_" .. case .. "}}}")
			end
		end
	end
	
	if not data.pron then
		table.insert(wikicode, "|- class=\"vsHide\"")
		table.insert(wikicode, "|")
		
		for _, number in ipairs(numbers) do
			table.insert(wikicode, "! colspan=\"" .. tostring(#columns) .. "\" | " .. mw.getContentLanguage():ucfirst(names[number]))
		end
	end
	
	for _, case in ipairs(cases) do
		table.insert(wikicode, "|- class=\"vsHide\"")
		table.insert(wikicode, "! style=\"min-width: 8em;\" | " .. mw.getContentLanguage():ucfirst(names[case]))
		
		if data.pron then
			table.insert(wikicode, "| colspan=\"" .. tostring(#columns) .. "\" | {{{" .. case .. "}}}")
		else
			for _, number in ipairs(numbers) do
				table.insert(wikicode, "| colspan=\"" .. tostring(#columns) .. "\" | {{{" .. number .. "_" .. case .. "}}}")
			end
		end
	end
	
	table.insert(wikicode, "|- class=\"vsHide\"")
	table.insert(wikicode, "! colspan=\"" .. tostring(#numbers * #columns + 1) .. "\" | Possessive forms")
	
	if not data.pron then
		table.insert(wikicode, "|- class=\"vsHide\"")
		table.insert(wikicode, "|")
		
		for _, number in ipairs(numbers) do
			table.insert(wikicode, "! colspan=\"" .. tostring(#columns) .. "\" | " .. mw.getContentLanguage():ucfirst(names[number]))
		end
	end
	
	table.insert(wikicode, "|- class=\"vsHide\"")
	table.insert(wikicode, "|")
	
	for _, number in ipairs(numbers) do
		for _, column in ipairs(columns) do
			table.insert(wikicode, "! style=\"min-width: 8em;\" | " .. mw.getContentLanguage():ucfirst(names[column]))
		end
	end
	
	for _, class in ipairs(classes) do
		table.insert(wikicode, "|- class=\"vsHide\"")
		table.insert(wikicode, "! " .. mw.getContentLanguage():ucfirst(names[class]))
		
		for _, number in ipairs(numbers) do
			for _, column in ipairs(columns) do
				table.insert(wikicode, "| {{{" .. (data.pron and "" or number .. "_") .. "poss_" .. column .. "_" .. class .. "}}}")
			end
		end
	end
	
	table.insert(wikicode, "|}")
	
	wikicode = table.concat(wikicode, "\n")
	
	return mw.ustring.gsub(wikicode, "{{{([a-z0-9_]+)}}}", repl)
end


return export