Module:izh-conj

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


local export = {}
local m_izh = require("Module:izh")

local function get_stem(word, ending)
	local found_ending = mw.ustring.match(word, ending .. "$")
	if found_ending then
		return mw.ustring.sub(word, 1, -mw.ustring.len(found_ending) - 1), found_ending
	end
	error("Unexpected ending for this inflection type! Wrong type?")
end

local function frontalize(w, vh)
	if vh == "ä" then
		w = mw.ustring.gsub(w, "[aou]", { a = "ä", o = "ö", u = "y" })
	end
	return w
end

local function elongate(stem, condition)
	if condition == nil or condition then
		-- already long?
		if mw.ustring.match(stem, m_izh.vowel .. m_izh.vowel .. "$") then
			for k, v in pairs(m_izh.vowel_sequences) do
				if mw.ustring.find(stem, v .. "$", pos) then
					return stem
				end
			end
		end
		return stem .. mw.ustring.sub(stem, -1)
	else
		return stem
	end
end

local function join(...)
	local t = {}
	for _, s in ipairs(arg) do
		if type(s) == "table" then
			for _, v in ipairs(s) do
				table.insert(t, v)
			end
		elseif type(s) == "string" then
			table.insert(t, s)
		end
	end
	return t
end

local function gsub_all(t, p, q)
	if type(t) == "string" then
		return mw.ustring.gsub(t, p, q)
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, mw.ustring.gsub(v, p, q))
	end
	return r
end

local function append(t, x)
	if not x then return t end
	if type(t) == "string" then
		return t .. x
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, v .. x)
	end
	return r
end

local function elongate_all(t)
	if type(t) == "string" then
		return elongate(t)
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, elongate(v))
	end
	return r
end

local function make_gradation(s, w)
	if s == w then
		return "no gradation"
	else
		return s .. "-" .. w .. " gradation"
	end
end

local function with_note(note, t)
	if not note then return t end
	if type(t) == "string" then
		return { { form = t, note = note } }
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, { form = v, note = note })
	end
	return r
end

local function will_geminate(forms, finalc, finalv)
	if type(forms) == "string" then
		local stem = forms .. finalc .. finalv
		local gem = m_izh.guess_gemination(stem)
		if not gem then return stem end
		return gem .. finalv
	end
	local r = {}
	for _, form in ipairs(forms) do
		table.insert(r, will_geminate(form, finalc, finalv))
	end
	return r
end

local function geminate_backwards(c)
	if mw.ustring.match(c, m_izh.vowel .. m_izh.consonant .. m_izh.vowel .. "$") then
		local stem = mw.ustring.sub(c, 1, -3)
		local finalc = mw.ustring.sub(c, -2, -2)
		local finalv = mw.ustring.sub(c, -1, -1)
		return will_geminate(stem, finalc, finalv)
	elseif mw.ustring.match(c, m_izh.vowel .. m_izh.consonant .. m_izh.vowel .. m_izh.vowel .. "$") then
		local stem = mw.ustring.sub(c, 1, -4)
		local finalc = mw.ustring.sub(c, -3, -3)
		local finalv = mw.ustring.sub(c, -2, -2)
		local finalv2 = mw.ustring.sub(c, -1, -1)
		return will_geminate(stem, finalc, finalv) .. finalv2
	else
		return c
	end
end

local function will_geminate_backwards(forms, addv)
	if type(forms) == "string" then
		return geminate_backwards(forms) .. addv
	end
	local r = {}
	for _, form in ipairs(forms) do
		table.insert(r, will_geminate_backwards(form, addv))
	end
	return r
end

local function elongate_and_geminate(c)
	return elongate(geminate_backwards(c))
end

local function elongate_and_geminate_all(t)
	if type(t) == "string" then
		return elongate_and_geminate(t)
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, elongate_and_geminate(v))
	end
	return r
end

local function can_geminate(data, forms, finalc, finalv)
	if data.geminate == false then
		return append(forms, finalc .. finalv)
	end
	return will_geminate(data, forms, finalc, finalv)
end

local function chiefly_in_dialect(...)
	if #arg == 1 then
		return "Chiefly in the " .. arg[1] .. " dialect."
	elseif #arg > 1 then
		return "Chiefly in the " .. require("Module:table").serialCommaJoin(arg) .. " dialects."
	else
		return 1
	end
end

local function get_any(stems)
	if type(stems) == "string" then
		return stems
	elseif type(stems) == "table" then
		return stems[1]
	end
end

local function process(data, result)
	local A = data.vh
	-- present stem (strong, weak)
	local pres_s = result.stem_pres_s or result.stem_pres
	local pres_w = result.stem_pres_w or result.stem_pres
	-- past stem (strong, weak)
	local past_s = result.stem_past_s or result.stem_past
	local past_w = result.stem_past_w or result.stem_past
	-- present passive stem
	local pres_v = result.stem_pres_v
	-- past passive stem
	local past_v = result.stem_past_v
	-- 1st infinitive stem
	local inf1 = result.stem_inf1 or pres_s
	-- 2nd infinitive
	local inf2 = result.stem_inf2 or pres_s
	-- 3rd infinitive / 3rd person stem
	local inf3 = result.stem_inf3 or pres_s
	-- conditional stem
	local cond = result.stem_cond or append(gsub_all(pres_s, "[ei]$", ""), "i")
	-- imperative stem
	local impr = result.stem_impr or pres_s
	-- potential stem
	local potn = result.stem_potn or append(pres_s, "n")
	-- present participle stem
	local pres_p = result.stem_pres_p or pres_s 
	-- past participle stem
	local past_p = result.stem_past_p or append(pres_s, "n")
	-- present third-person singular stem 
	local pres_3sg = result.stem_pres_3sg or inf3
	if pres_3sg ~= geminate_backwards(pres_3sg) then
		result.geminate = true
	end

	result.pres_part = append(pres_p, "v" .. A)
	result.pres_pasv_part = append(past_v, A .. "v" .. A)
	result.past_part = join(gsub_all(append(past_p, "t"), "([lnprs])[lnprs]t$", "%1t"), append(past_p, frontalize("ut", A)))
	result.past_part_pl = append(geminate_backwards(append(past_p, "ee")), "t")
	result.past_pasv_part = append(past_v, frontalize("u", A))

	result.pres_pasv = geminate_backwards(append(pres_v, A .. A))
	result.pres_1sg = append(pres_w, "n")
	result.pres_2sg = append(pres_w, "t")
	result.pres_3sg = append(elongate_and_geminate_all(pres_3sg), result.monosyllabic and "p" or nil)
	result.pres_1pl = append(pres_w, "mm" .. A)
	result.pres_2pl = append(pres_w, "tt" .. A)
	result.pres_3pl = join(
		not result.monosyllabic and with_note(chiefly_in_dialect("Soikkola"),
			append(result.pres_3sg, "t")),
		with_note(not result.monosyllabic and chiefly_in_dialect("Ala-Laukaa"),
			append(pres_s, "v" .. A .. "t")),
		result.pres_pasv)
	result.pres_conn = pres_w
	result.pres_pasv_conn = append(pres_v, A)

	result.past_pasv = append(past_v, "ii")
	result.past_1sg = append(past_w, "n")
	result.past_2sg = append(past_w, "t")
	if result.has_short_past_2sg then
		result.past_2sg = join(result.past_2sg, with_note(chiefly_in_dialect("Soikkola"), append(elongate_and_geminate_all(get_stem(past_w, "si")), "st")))
	end
	result.past_3sg = past_s
	result.past_1pl = append(past_w, "mm" .. A)
	result.past_2pl = append(past_w, "tt" .. A)
	result.past_3pl = join(
		not result.monosyllabic and with_note(chiefly_in_dialect("Soikkola"),
			append(elongate_and_geminate_all(result.past_3sg), "t")),
		with_note(not result.monosyllabic and chiefly_in_dialect("Ala-Laukaa"),
			append(past_s, "v" .. A .. "t")),
		result.past_pasv)
	result.past_conn = result.past_part
	result.past_conn_pl = result.past_part_pl
	result.past_pasv_conn = result.past_pasv_part

	result.cond_pasv = append(past_v, A .. "is")
	result.cond_1sg = append(cond, "sin")
	result.cond_2sg = join(append(cond, "sit"), with_note(chiefly_in_dialect("Soikkola"), append(elongate_and_geminate_all(cond), "st")))
	result.cond_3sg = append(cond, "s")
	result.cond_1pl = append(cond, "simm" .. A)
	result.cond_2pl = append(cond, "sitt" .. A)
	result.cond_3pl = join(
		with_note(chiefly_in_dialect("Soikkola"), append(cond, "siit")),
		with_note(chiefly_in_dialect("Ala-Laukaa"), append(cond, "siv" .. A .. "t")),
		result.cond_pasv)
	result.cond_conn = result.cond_3sg
	result.cond_pasv_conn = result.cond_pasv

	result.impr_pasv = append(will_geminate(past_v .. A, "k", frontalize("o", A)), frontalize("o", A))
	result.impr_2sg = pres_w
	result.impr_3sg = append(will_geminate(impr, "k", frontalize("o", A)), frontalize("o", A))
	result.impr_2pl = append(will_geminate(impr, "k", A), A)
	result.impr_3pl = append(result.impr_3sg, "t")
	result.impr_conn = append(impr, frontalize("ko", A))
	result.impr_pasv_conn = append(past_v, frontalize("ako", A))

	result.potn_pasv = will_geminate_backwards(append(past_v, frontalize("ano", A)), frontalize("o", A))
	result.potn_1sg = append(potn, "en")
	result.potn_2sg = append(potn, "et")
	result.potn_3sg = will_geminate_backwards(append(potn, frontalize("o", A)), frontalize("o", A))
	result.potn_1pl = append(potn, "emm" .. A)
	result.potn_2pl = append(potn, "ett" .. A)
	result.potn_3pl = append(result.potn_3sg, "t")
	result.potn_conn = append(potn, "e")
	result.potn_pasv_conn = append(past_v, A .. "ne")

	result.inf1 = { data.title }
	result.inf2_ine = inf2
	if m_izh.guess_elongation(get_any(result.inf2_ine) .. "e") then
		result.inf2_ine = append(result.inf2_ine, "e")
		if mw.ustring.match(result.inf2_ine, m_izh.vowel .. m_izh.vowel .. "$") then
			result.inf2_ine = mw.ustring.sub(result.inf2_ine, 1, -2) .. "jees"
		else
			result.inf2_ine = result.inf2_ine .. "es"
		end
	else
		-- potentially geminate
		result.inf2_ine = will_geminate_backwards(result.inf2_ine, "es")
	end
	result.inf2_ins = will_geminate_backwards(inf2, "en")
	result.inf3_ill = append(will_geminate(inf3, "m", A), A)
	result.inf3_ine = append(inf3, "m" .. A .. (m_izh.guess_elongation(inf3 .. "m" .. A) and A or "") .. "s")
	result.inf3_ela = append(inf3, "m" .. A .. "st")
	result.inf3_abe = append(inf3, "m" .. A .. "t" .. A)
	result.inf4_nom = append(inf3, "miin")
	result.inf4_par = join(append(inf3, "mist" .. A), append(inf3, "mist"))

	if result.short_past_3sg then
		result.past_3sg = gsub_all(result.past_3sg, "i$", "")
	end

	-- cleanup virtual syllable breaks
	for k, v in pairs(result) do
		if type(v) == "string" then
			result[k] = mw.ustring.gsub(v, m_izh.virtual_syllable_break, "")
		elseif type(v) == "table" then
			for i, f in ipairs(v) do
				if type(f) == "table" and f.form then
					f.form = mw.ustring.gsub(f.form, m_izh.virtual_syllable_break, "")
				elseif type(f) == "string" then
					v[i] = mw.ustring.gsub(f, m_izh.virtual_syllable_break, "")
				end
			end
		end
	end
	return result
end

local function ungeminate(data, result, strong, weak, stem)
	if data.geminate ~= false and mw.ustring.len(strong) == 1 then
		-- gemination
		local final = strong
		if final == "j" then
			final = "i"
		end
		
		if mw.ustring.match(stem, final .. "$") then
			result.geminate = true
			return get_stem(stem, final)
		end
	end
	return stem
end

-- inflection classes begin
local inflections = {}

inflections["ampua"] = function (data)
	local result = { typeno = "1" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local final = mw.ustring.sub(word, -2, -2)
	local stem = ungeminate(data, result, strong, weak, get_stem(word, strong .. final .. vh))

	if strong ~= "" and weak == "" then weak = m_izh.virtual_syllable_break end
	result.stem_pres_s = stem .. strong .. final
	result.stem_pres_w = stem .. weak .. final
	result.stem_past_s = stem .. strong .. final .. "i"
	result.stem_past_w = stem .. weak .. final .. "i"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["kirjuttaa"] = function (data)
	local result = { typeno = "2" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "aa", vh)))

	if strong ~= "" and weak == "" then weak = m_izh.virtual_syllable_break end
	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["kyntää"] = function (data)
	local result = { typeno = "3" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = get_stem(word, frontalize(strong .. "aa", vh))
	if not mw.ustring.match(strong, "t$") then error("unsupported stem for kyntää") end

	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past = stem .. mw.ustring.sub(strong, 1, -2) .. "si"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["antaa"] = function (data)
	local result = { typeno = "4" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "aa", vh)))

	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past_s = stem .. strong .. frontalize("oi", vh)
	result.stem_past_w = stem .. weak .. frontalize("oi", vh)
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["laskia"] = function (data)
	local result = { typeno = "5" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	result.stem_pres_s = stem .. strong .. "e"
	result.stem_pres_w = stem .. weak .. "e"
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf2 = stem .. strong .. "i"
	result.stem_inf3 = stem .. strong .. frontalize("o", vh)
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["tuntia"] = function (data)
	local result = { typeno = "6" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	local past_stem = {
		["nt"] = "ns",
		["ht"] = "ks"
	}

	result.stem_pres_s = stem .. strong .. "e"
	result.stem_pres_w = stem .. weak .. "e"
	result.stem_past = stem .. (past_stem[strong] or error("The tuntia type is not supported for this verb")) .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf2 = stem .. strong .. "i"
	result.stem_inf3 = stem .. strong .. frontalize("o", vh)
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["oppia"] = function (data)
	local result = { typeno = "7" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	result.stem_pres_s = stem .. strong .. "i"
	result.stem_pres_w = stem .. weak .. "i"
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "it"
	result.stem_past_v = stem .. weak .. "itt"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["astavoija"] = function(data)
	local result = { typeno = "7" }
	local word = data.title
	local weak = data.args[1] or error("must specify strong grade")
	local strong = data.args[2] or error("must specify weak grade")
	local vh = data.vh
	local final = mw.ustring.sub(word, -4, -4)
	local stem = get_stem(word, weak .. final .. frontalize("ija", vh))
	
	result.stem_pres_s = stem .. strong .. final .. "i"
	result.stem_pres_w = stem .. weak .. final .. "i"
	result.stem_past_s = stem .. strong .. final .. "i"
	result.stem_past_w = stem .. weak .. final .. "i"
	result.stem_pres_v = stem .. weak .. final .. "it"
	result.stem_past_v = stem .. weak .. final .. "itt"
	result.stem_inf2 = stem .. weak .. final .. "ij"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["voija"] = function (data)
	local result = { typeno = "8" }
	local word = data.title
	local vh = data.vh
	local final = mw.ustring.sub(word, -3, -3)
	local stem = get_stem(word, final .. frontalize("ja", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the voija type") end

	result.stem_pres = stem .. final
	result.stem_past = stem .. "i"
	result.stem_pres_v = stem .. final .. "j"
	result.stem_past_v = stem .. final .. "t"
	result.stem_inf2 = stem .. final .. "j"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["jäävvä"] = function (data)
	local result = { typeno = "9" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("vva", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the jäävvä type") end

	result.stem_pres = stem
	result.stem_past = mw.ustring.sub(stem, 1, -2) .. "i"
	result.stem_pres_v = stem .. "vv"
	result.stem_past_v = stem .. "t"
	result.stem_cond = result.stem_past
	result.stem_inf2 = stem .. "vv"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["käyvvä"] = function (data)
	local result = { typeno = "10" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("vva", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the käyvvä type") end

	result.stem_pres = stem
	result.stem_past = mw.ustring.sub(stem, 1, -2) .. "i"
	result.stem_pres_v = stem .. "vv"
	result.stem_past_v = stem .. "t"
	result.stem_cond = result.stem_past
	result.stem_inf2 = stem .. "vv"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["pessä"] = function (data)
	local result = { typeno = "11" }
	local word = data.title
	local weak = data.args[1] or nil
	local strong = data.args[2] or nil
	local vh = data.vh
	local final_cons = mw.ustring.sub(word, -2, -2)
	local stem = get_stem(word, final_cons .. final_cons .. frontalize("a", vh))

	if weak and not strong then error("must specify either both the weak and strong grade or neither") end

	local stem_s, stem_w
	if strong and weak then
		local final_vowels
		stem, final_vowels = get_stem(stem, m_izh.vowel .. "+")
		stem = get_stem(stem, weak)
		stem_s = stem .. strong .. final_vowels
		stem_w = stem .. weak .. final_vowels
	else
		stem_s, stem_w = stem, stem
	end

	result.stem_pres_s = stem_s .. final_cons .. "e"
	result.stem_pres_w = stem_s .. final_cons .. "e"
	result.stem_past_s = stem_s .. final_cons .. "i"
	result.stem_past_w = stem_s .. final_cons .. "i"
	result.stem_pres_v = stem_w .. final_cons .. final_cons
	result.stem_past_v = stem_w .. final_cons .. "t"
	result.stem_inf2 = stem_w .. final_cons .. final_cons
	result.stem_inf3 = stem_s .. final_cons .. frontalize("o", vh)
	result.stem_potn = stem_w .. final_cons .. final_cons
	result.stem_impr = stem_w .. final_cons
	result.stem_past_p = stem_w .. final_cons .. final_cons
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["kuulla"] = function (data)
	local result = { typeno = "12" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, vh)
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local finalgem = mw.ustring.sub(stem, -2, -1)
	local finals = {
		["ll"] = "l",
		["nn"] = "n",
		["rr"] = "r"
	}
	local final = finals[finalgem] or error("Unsupported stem for kuulla")
	stem = get_stem(stem, finalgem)
	local prefinal = mw.ustring.sub(stem, -1, -1)
	stem = get_stem(stem, weak .. prefinal)
	final = prefinal .. final
	finalgem = prefinal .. finalgem

	result.stem_pres = stem .. strong .. final .. "e"
	result.stem_past = stem .. strong .. final .. "i"
	result.stem_pres_v = stem .. weak .. finalgem
	result.stem_past_v = stem .. weak .. final .. "t"
	result.stem_inf2 = stem .. weak .. finalgem
	result.stem_inf3 = stem .. strong .. final .. frontalize("o", vh)
	result.stem_potn = stem .. weak .. finalgem
	result.stem_impr = stem .. weak .. final
	result.stem_past_p = stem .. weak .. finalgem
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["valita"] = function (data)
	local result = { typeno = "13" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))

	result.stem_pres = stem .. "tse"
	result.stem_past = stem .. "tsi"
	result.stem_pres_v = stem .. "t"
	result.stem_past_v = stem .. "tt"
	result.stem_inf2 = stem .. "t"
	result.stem_inf3 = stem .. frontalize("tso", vh)
	result.stem_potn = stem .. "nn"
	result.stem_impr = stem .. "t"
	result.stem_past_p = stem .. "n"
	
	return process(data, result)
end

inflections["joossa"] = function (data)
	local result = { typeno = "14" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))

	result.stem_pres = stem .. "kse"
	result.stem_past = stem .. "ksi"
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf2 = stem .. "ss"
	result.stem_inf3 = stem .. frontalize("kso", vh)
	result.stem_potn = stem .. "ss"
	result.stem_impr = stem .. "s"
	result.stem_past_p = stem .. "ss"
	
	return process(data, result)
end

inflections["valeta"] = function (data)
	local result = { typeno = "15" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = mw.ustring.sub(stem, -1, -1)
	stem = get_stem(stem, weak .. final)

	result.stem_pres = stem .. strong .. "ene"
	result.stem_past = stem .. strong .. "eni"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	result.stem_inf2 = stem .. weak .. final .. "t"
	result.stem_inf3 = stem .. strong .. "en" .. frontalize("o", vh)
	result.stem_impr = stem .. weak .. final .. "t"
	result.stem_potn = stem .. weak .. "en"
	result.stem_past_p = stem .. weak .. "enn"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["maata"] = function (data)
	local result = { typeno = "16" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = mw.ustring.sub(stem, -1, -1)
	stem = get_stem(stem, weak .. final)
	
	local gem = will_geminate(stem, strong, final)
	if gem ~= stem .. strong .. final then
		result.geminate = true
	end

	result.stem_pres = gem .. final
	result.stem_past = stem .. strong .. (final ~= "i" and final or "") .. "isi"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	result.stem_inf1 = stem .. strong .. final
	result.stem_inf2 = stem .. weak .. final .. "t"
	result.stem_inf3 = result.stem_pres_w
	result.stem_cond = stem .. strong .. final .. "j" .. vh .. "i"
	result.stem_impr = stem .. weak .. final .. "t"
	result.stem_potn = stem .. weak .. final .. "nn"
	result.stem_pres_p = result.stem_pres_w
	result.stem_past_p = stem .. weak .. final .. "nn"
	result.stem_pres_3sg = stem .. strong .. final .. "j" .. vh

	result.short_past_3sg = true
	result.has_short_past_2sg = true

	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["hävetä"] = function (data)
	local result = { typeno = "16" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("eta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = "i"
	stem = get_stem(stem, weak)
	
	local gem = will_geminate(stem, strong, final)
	if gem ~= stem .. strong .. final then
		result.geminate = true
	end

	result.stem_pres = gem .. final
	result.stem_past = stem .. strong .. "isi"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf1 = stem .. strong .. final
	result.stem_inf2 = stem .. weak .. "et"
	result.stem_inf3 = result.stem_pres_w
	result.stem_cond = stem .. strong .. final .. "j" .. vh .. "i"
	result.stem_impr = stem .. weak .. "et"
	result.stem_potn = stem .. weak .. "enn"
	result.stem_pres_p = result.stem_pres_w
	result.stem_past_p = stem .. weak .. "enn"
	result.stem_pres_3sg = stem .. strong .. final .. "j" .. vh

	result.short_past_3sg = true
	result.has_short_past_2sg = true

	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["laskiissa"] = function (data)
	local result = { typeno = "17" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("issa", vh))
	local final = mw.ustring.sub(stem, -1, -1)

	result.stem_pres_s = stem .. final
	result.stem_pres_w = stem .. final
	result.stem_past = stem .. "isi"
	result.stem_past_s = stem .. "isi"
	result.stem_pres_v = stem .. "iss"
	result.stem_past_v = stem .. "ist"
	result.stem_inf2 = stem .. "iss"
	result.stem_inf3 = stem .. "i"
	result.stem_impr = stem .. "is"
	result.stem_potn = stem .. "iss"
	result.stem_cond = stem .. "ij" .. vh .. "i"
	result.stem_pres_p = stem .. "i"
	result.stem_past_p = stem .. "iss"
	result.stem_pres_3sg = stem .. "ij" .. vh
	
	result.short_past_3sg = true
	result.has_short_past_2sg = true
	return process(data, result)
end

inflections["praavihussa"] = function (data)
	local result = { typeno = "18" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))

	result.stem_pres = stem
	if mw.ustring.sub(stem, -2, -2) == mw.ustring.sub(stem, -1, -1) then
		result.stem_past = mw.ustring.sub(stem, 1, -2) .. "i"
	else
		result.stem_past = stem .. "i"
	end
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf2 = stem .. "ss"
	result.stem_impr = stem .. "s"
	result.stem_potn = stem .. "ss"
	result.stem_past_p = stem .. "ss"

	return process(data, result)
end

-- inflection classes end

local conj_table = [=[{| class="inflection-table vsSwitcher izh-conj" data-toggle-category="conjugation"
|-
! colspan=6 class="vsToggleElement izh-conj-header-toggle"| Conjugation of {{{title}}} (<span class="izh-conj-type">{{{type}}}</span>)
|- class="vsHide"
! colspan=6 class="izh-conj-header-tense" | [[indicative mood|Indikativa]]
|- class="vsHide"
! colspan=3 class="izh-conj-header-tense" | [[present tense|Preesens]]
! colspan=3 class="izh-conj-header-tense" | [[perfect|Perfekta]]
|- class="vsHide"
! class="izh-conj-header-tense" |
! class="izh-conj-header-posneg thsub" | positive
! class="izh-conj-header-posneg thsub" | negative
! class="izh-conj-header-tense" |
! class="izh-conj-header-posneg thsub" | positive
! class="izh-conj-header-posneg thsub" | negative
|- class="vsHide"
! class="izh-conj-header-person" | 1st singular
| {{{pres_1sg}}}
| {{{en !pres_conn}}}
! class="izh-conj-header-person" | 1st singular
| {{{oon !past_part}}}
| {{{en oo !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd singular
| {{{pres_2sg}}}
| {{{et !pres_conn}}}
! class="izh-conj-header-person" | 2nd singular
| {{{oot !past_part}}}
| {{{et oo !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd singular
| {{{pres_3sg}}}
| {{{ei !pres_conn}}}
! class="izh-conj-header-person" | 3rd singular
| {{{ono !past_part}}}
| {{{ei oo !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 1st plural
| {{{pres_1pl}}}
| {{{emmä !pres_conn}}}
! class="izh-conj-header-person" | 1st plural
| {{{oomma !past_part_pl}}}
| {{{emmä oo !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd plural
| {{{pres_2pl}}}
| {{{että !pres_conn}}}
! class="izh-conj-header-person" | 2nd plural
| {{{ootta !past_part_pl}}}
| {{{että oo !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd plural
| {{{pres_3pl}}}
| {{{evät !pres_conn}}}, {{{ei !pres_pasv_conn}}}
! class="izh-conj-header-person" | 3rd plural
| {{{ovat !past_part_pl}}}
| {{{evät oo !past_part_pl}}}, {{{ei oo !past_pasv_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | impersonal
| {{{pres_pasv}}}
| {{{ei !pres_pasv_conn}}}
! class="izh-conj-header-person" | impersonal
| {{{ono !past_pasv_part}}}
| {{{ei oo !past_pasv_part}}}
|- class="vsHide"
! colspan=3 class="izh-conj-header-person" | [[past tense|Imperfekta]]
! colspan=3 class="izh-conj-header-person" | [[pluperfect|Pluskvamperfekta]]
|- class="vsHide"
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
|- class="vsHide"
! class="izh-conj-header-person" | 1st singular
| {{{past_1sg}}}
| {{{en !past_conn}}}
! class="izh-conj-header-person" | 1st singular
| {{{olin !past_part}}}
| {{{en olt !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd singular
| {{{past_2sg}}}
| {{{et !past_conn}}}
! class="izh-conj-header-person" | 2nd singular
| {{{olit !past_part}}}
| {{{et olt !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd singular
| {{{past_3sg}}}
| {{{ei !past_conn}}}
! class="izh-conj-header-person" | 3rd singular
| {{{oli !past_part}}}
| {{{ei olt !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 1st plural
| {{{past_1pl}}}
| {{{emmä !past_conn_pl}}}
! class="izh-conj-header-person" | 1st plural
| {{{olimma !past_part_pl}}}
| {{{emmä olleet !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd plural
| {{{past_2pl}}}
| {{{että !past_conn_pl}}}
! class="izh-conj-header-person" | 2nd plural
| {{{olitta !past_part_pl}}}
| {{{että olleet !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd plural
| {{{past_3pl}}}
| {{{evät !past_conn_pl}}}, {{{ei !past_pasv_conn}}}
! class="izh-conj-header-person" | 3rd plural
| {{{olivat !past_part_pl}}}
| {{{evät olleet !past_part_pl}}}, {{{ei olt !past_pasv_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | impersonal
| {{{past_pasv}}}
| {{{ei !past_pasv_conn}}}
! class="izh-conj-header-person" | impersonal
| {{{oli !past_pasv_part}}}
| {{{ei olt !past_pasv_part}}}
|- class="vsHide"
! colspan=6 class="izh-conj-header-person" | [[conditional mood|Konditsionala]]
|- class="vsHide"
! colspan=3 class="izh-conj-header-person" | [[present tense|Preesens]]
! colspan=3 class="izh-conj-header-person" | [[perfect|Perfekta]]
|- class="vsHide"
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
|- class="vsHide"
! class="izh-conj-header-person" | 1st singular
| {{{cond_1sg}}}
| {{{en !cond_conn}}}
! class="izh-conj-header-person" | 1st singular
| {{{olisin !past_part}}}
| {{{en olis !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd singular
| {{{cond_2sg}}}
| {{{et !cond_conn}}}
! class="izh-conj-header-person" | 2nd singular
| {{{olisit !past_part}}}
| {{{et olis !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd singular
| {{{cond_3sg}}}
| {{{ei !cond_conn}}}
! class="izh-conj-header-person" | 3rd singular
| {{{olis !past_part}}}
| {{{ei olis !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 1st plural
| {{{cond_1pl}}}
| {{{emmä !cond_conn}}}
! class="izh-conj-header-person" | 1st plural
| {{{olisimma !past_part_pl}}}
| {{{emmä olis !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd plural
| {{{cond_2pl}}}
| {{{että !cond_conn}}}
! class="izh-conj-header-person" | 2nd plural
| {{{olisitta !past_part_pl}}}
| {{{että olis !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd plural
| {{{cond_3pl}}}
| {{{evät !cond_conn}}}, {{{ei !cond_pasv_conn}}}
! class="izh-conj-header-person" | 3rd plural
| {{{olisivat !past_part_pl}}}
| {{{evät olis !past_part_pl}}}, {{{ei olis !past_pasv_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | impersonal
| {{{cond_pasv}}}
| {{{ei !cond_pasv_conn}}}
! class="izh-conj-header-person" | impersonal
| {{{olis !past_pasv_part}}}
| {{{ei olis !past_pasv_part}}}
|- class="vsHide"
! colspan=6 class="izh-conj-header-person" | [[imperative mood|Imperativa]]
|- class="vsHide"
! colspan=3 class="izh-conj-header-person" | [[present tense|Preesens]]
! colspan=3 class="izh-conj-header-person" | [[perfect|Perfekta]]
|- class="vsHide"
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
|- class="vsHide"
! class="izh-conj-header-person" | 1st singular
| —
| —
! class="izh-conj-header-person" | 1st singular
| —
| —
|- class="vsHide"
! class="izh-conj-header-person" | 2nd singular
| {{{impr_2sg}}}
| {{{elä !pres_conn}}}
! class="izh-conj-header-person" | 2nd singular
| {{{oo !past_part}}}
| {{{elä oo !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd singular
| {{{impr_3sg}}}
| {{{elköö !impr_conn}}}
! class="izh-conj-header-person" | 3rd singular
| {{{olkoo !past_part}}}
| {{{elköö olko !past_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | 1st plural
| —
| —
! class="izh-conj-header-person" | 1st plural
| —
| —
|- class="vsHide"
! class="izh-conj-header-person" | 2nd plural
| {{{impr_2pl}}}
| {{{elkää !impr_conn}}}
! class="izh-conj-header-person" | 2nd plural
| {{{olkaa !past_part_pl}}}
| {{{elkää olko !past_part_pl}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd plural
| {{{impr_3pl}}}
| {{{elkööt !impr_conn}}}, {{{elköö !impr_pasv_conn}}}
! class="izh-conj-header-person" | 3rd plural
| {{{olkoot !past_part_pl}}}
| {{{elkööt olko !past_part_pl}}}, {{{elköö olko !past_pasv_part}}}
|- class="vsHide"
! class="izh-conj-header-person" | impersonal
| {{{impr_pasv}}}
| {{{elköö !impr_pasv_conn}}}
! class="izh-conj-header-person" | impersonal
| {{{olkoo !past_pasv_part}}}
| {{{elköö olko !past_pasv_part}}}
|- class="vsHide"
! colspan=6 class="izh-conj-header-person" | [[potential mood|Potentsiala]]
|- class="vsHide"
! colspan=3 class="izh-conj-header-person" | [[present tense|Preesens]]
! rowspan=9 colspan=3 class="izh-conj-header-person" |
|- class="vsHide"
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | positive
! class="izh-conj-header-person thsub" | negative
|- class="vsHide"
! class="izh-conj-header-person" | 1st singular
| {{{potn_1sg}}}
| {{{en !potn_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd singular
| {{{potn_2sg}}}
| {{{et !potn_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd singular
| {{{potn_3sg}}}
| {{{ei !potn_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | 1st plural
| {{{potn_1pl}}}
| {{{emmä !potn_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | 2nd plural
| {{{potn_2pl}}}
| {{{että !potn_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | 3rd plural
| {{{potn_3pl}}}
| {{{evät !potn_conn}}}, {{{ei !potn_pasv_conn}}}
|- class="vsHide"
! class="izh-conj-header-person" | impersonal
| {{{potn_pasv}}}
| {{{ei !potn_pasv_conn}}}
|- class="vsHide"
! colspan=6 class="izh-conj-header-person" | Nominal forms
|- class="vsHide"
! colspan=3 class="izh-conj-header-person" | [[infinitive|Infinitivat]]
! colspan=3 class="izh-conj-header-person" | [[participle|Partisipat]]
|- class="vsHide"
! colspan=2 class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" |
! class="izh-conj-header-person" |
! class="izh-conj-header-person thsub" | active
! class="izh-conj-header-person thsub" | passive
|- class="vsHide"
! colspan=2 class="izh-conj-header-person" | 1st
| {{{inf1}}}
! class="izh-conj-header-person" | present
| {{{pres_part}}}
| {{{pres_pasv_part}}}
|- class="vsHide"
! rowspan=2 class="izh-conj-header-person" | 2nd
! class="izh-conj-header-person thsub" | inessive
| {{{inf2_ine}}}
! class="izh-conj-header-person" | past
| {{{past_part}}}
| {{{past_pasv_part}}}
|- class="vsHide"
! class="izh-conj-header-person thsub" | instructive
| {{{inf2_ins}}}
| colspan=3 rowspan=7 class="izh-conj-notes" | {{{notes}}}
|- class="vsHide"
! rowspan=4 class="izh-conj-header-person" | 3rd
! class="izh-conj-header-person thsub" | illative
| {{{inf3_ill}}}
|- class="vsHide"
! class="izh-conj-header-person thsub" | inessive
| {{{inf3_ine}}}
|- class="vsHide"
! class="izh-conj-header-person thsub" | elative
| {{{inf3_ela}}}
|- class="vsHide"
! class="izh-conj-header-person thsub" | abessive
| {{{inf3_abe}}}
|- class="vsHide"
! rowspan=4 class="izh-conj-header-person" | 4th
! class="izh-conj-header-person thsub" | nominative
| {{{inf4_nom}}}
|- class="vsHide"
! class="izh-conj-header-person thsub" | partitive
| {{{inf4_par}}}
|}]=]

local function tag(text)
	return require("Module:script utilities").tag_text(text, m_izh.lang, nil, "term")
end

local function link(text, prefix)
	return require("Module:script utilities").tag_text((prefix and prefix or "") .. require("Module:links").language_link{ term = text, lang = m_izh.lang }, m_izh.lang)
end

local function mention(text)
	return require("Module:links").full_link({ term = text, lang = m_izh.lang }, "term")
end

local function help_tooltip(text)
	return "<sup>" .. tostring(mw.html.create("span"):attr("style", "cursor:help"):attr("title", text):wikitext("?")) .. "</sup>"
end

local function note_reference(note)
	if note then
		return "<sup>" .. note .. ")</sup>"
	else
		return ""
	end
end

local function link_and_note(form, prefix)
	if type(form) == "table" then
		return link(form.form, prefix) .. note_reference(form.note)
	else
		return link(form, prefix)
	end
end

local function note_text(reference, text)
	return note_reference(reference) .. " " .. text
end

-- extract notes from forms into a list and replace by their index
local function format_notes_for_form(forms, form)
	local note = form.note
	if note then
		local index = forms.notes_reverse[note]
		if index then
			form.note = index
		else
			index = tostring(#forms.notes + 1)
			table.insert(forms.notes, note)
			forms.notes_reverse[note] = index
			form.note = index
		end
	end
end

local function format_notes(forms)
	forms.notes = {}
	forms.notes_reverse = {}
	for k, v in pairs(forms) do
		if type(v) == "table" then
			if v[1] then
				for _, form in ipairs(v) do
					if type(form) == "table" then
						format_notes_for_form(forms, form)
					end
				end
			else
				format_notes_for_form(forms, v)
			end
		end
	end
	forms.notes_reverse = nil
end

function export.raw(word, infl_type, grad1, grad2, args)
	if not infl_type then error("inflection class not specified") end
	args = args or {}

	local infl = inflections[infl_type] or error("unsupported inflection type")
	local geminate, vh
	if args["g"] == "1" then
		geminate = true
	elseif args["g"] == "0" or args["g"] == "-" then
		geminate = false
	end
	
	if args["v"] then
		vh = args["v"]
		if vh ~= "a" and vh ~= "ä" then
			error("Invalid vowel harmony specification")
		end
	else
		vh = m_izh.guess_vowel_harmony(word)
	end

	args[1] = args[1] or grad1
	args[2] = args[2] or grad2
	local data = { title = word, geminate = geminate, vh = vh, args = args }
	return infl(data)
end

function export.show(frame)
	local infl_type = frame.args[1] or error("inflection class not specified")
	local infl = inflections[infl_type] or error("unsupported inflection type")
	local args = frame:getParent().args
	local title = args["title"] or mw.title.getCurrentTitle().text

	local geminate, vh
	if args["g"] == "1" then
		geminate = true
	elseif args["g"] == "0" or args["g"] == "-" then
		geminate = false
	end
	
	if args["v"] then
		vh = args["v"]
		if vh ~= "a" and vh ~= "ä" then
			error("Invalid vowel harmony specification")
		end
	else
		vh = m_izh.guess_vowel_harmony(title)
	end

	local data = { title = title, geminate = geminate, vh = vh, args = args }

	local forms = infl(data)
	format_notes(forms)

	local function repl(form)
		local prefix = nil
		if form == "title" then
			return "'''" .. title .. "'''"
		elseif form == "type" then
			if forms.irregular then
				return "irregular"
			end
			local s = "type " .. forms.typeno .. "/" .. mention(infl_type)
			if forms.grade then
				s = s .. ", " .. forms.grade
			else
				s = s .. ", " .. make_gradation(nil, nil)
			end
			if forms.geminate then
				s = s .. ", gemination"
			end
			return s
		elseif form == "notes" then
			local results = {}
			for index, note in ipairs(forms.notes) do
				table.insert(results, note_text(tostring(index), note))
			end
			table.insert(results, note_text("*",
				"For the imperative, the 2nd plural (" .. tag(forms.impr_2pl) .. ") may be used for the 3rd person as well."))
			table.insert(results, note_text("**",
				"The interrogative is formed by adding the suffix {{m|izh|-k}} ({{m|izh|-ka}}" .. help_tooltip("in back-vocalic stems, following the consonant -t") .. "/{{m|izh|-kä}}" .. help_tooltip("in front-vocalic stems, following the consonant -t") .. ") to the indicative"))
			table.insert(results, note_text("***",
				"The deliberative is formed by adding the suffix {{m|izh|-k}} ({{m|izh|-ka}}" .. help_tooltip("in back-vocalic stems, following the consonant -t") .. "/{{m|izh|-kä}}" .. help_tooltip("in front-vocalic stems, following the consonant -t") .. ") or {{m|izh|-kse}} to either the indicative or the potential"))
			table.insert(results, note_text("****",
				"In folk poetry, a long first infinitive can be formed by adding the suffix ''[[-ks#Ingrian|-kse-]]'', followed by possessive suffixes, to the first infinitive. Note that sometimes gemination may be undone by this addition."))
			return table.concat(results, "<br />")
		elseif mw.ustring.find(form, "!") then
			local excl = mw.ustring.find(form, "!")
			prefix = mw.ustring.sub(form, 1, excl - 1)
			form = mw.ustring.sub(form, excl + 1)
		end
		local value = forms[form]
		if not value then
			return "&mdash;"
		elseif type(value) == "table" and value[1] then
			local result = {}
			for _, f in ipairs(value) do
				table.insert(result, link_and_note(f, prefix))
			end
			return table.concat(result, ", ")
		else
			return link_and_note(value, prefix)
		end
	end

	local result = mw.ustring.gsub(conj_table, "{{{([a-z0-9äö _:!]+)}}}", repl)
	result = mw.ustring.gsub(result, "{{m|izh|([^}]-)}}", mention)
	return result
		.. require("Module:TemplateStyles")("Module:izh-conj/style.css")
end

return export