Module:sa-headword

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

This module powers all Sanskrit headword-line templates. All of them support at least the following arguments:

|head=, |head2=, |head3=, ...
Explicitly specified headword(s), for introducing links in multiword expressions. Note that by default each word of a multiword lemma is linked, so you only need to use this when the default links don't suffice (e.g. the multiword expression consists of non-lemma forms, which need to be linked to their lemmas).
|tr=, |tr2=, |tr3=, ...
Manual transliteration(s), in case the automatic transliteration is incorrect.
|sc=
Script code. Rarely needs to be given, as the script is normally autodetected.
|sort=
Sort key. Rarely needs to be given, as the sort key is autogenerated and is usually correct.
|id=
Sense ID code, for linking to this headword. See {{senseid}}. Only needed for distinguishing multiple Sanskrit headwords on the same page.

NOTE: All headword templates that go through Module:sa-headword automatically add the page to a script-specific category for the part of speech in question, in addition to the normal part of speech category. For example, {{sa-noun form}} when used with a term in Devanagari script automatically adds the page to both Category:Sanskrit noun forms and Category:Sanskrit noun forms in Devanagari script (regardless of whether |sc= was explicitly given; if not given, the correct script is autodetected).


For participles,|2= can be one of "gerundive", "perfect"/"perf", "future"/"fut", "present"/"pres", or "past". |3= can be one of "active"/"act"/"a", "mediopassive"/"mediopass"/"mp", or "passive"/"pass"/"p". Adding these parameters will categorize the page correctly and add a gloss to the headword line.


local export = {}
local pos_functions = {}
local m_links = require("Module:links")

local lang = require("Module:languages").getByCode("sa")
local langname = lang:getCanonicalName()
local PAGENAME = mw.title.getCurrentTitle().text
local Array = require "Module:array"

local boolean = {type = "boolean"}
local list = {list = true}

local suffix_categories = {
	["adjectives"] = true,
	["adverbs"] = true,
	["nouns"] = true,
	["verbs"] = true,
}

local function track(page)
	require("Module:debug").track("sa-headword/" .. page)
	return true
end

local function glossary_link(entry, text)
	text = text or entry
	return "[[Appendix:Glossary#" .. entry .. "|" .. text .. "]]"
end

function export.alt(frame)
	local args = frame:getParent().args
	local currentScript = lang:findBestScript(PAGENAME)
	local currentScriptCode = currentScript:getCode()
	local availableScripts = lang:getScripts()
	local devaForm = args["Deva"] or currentScriptCode == "Deva" and PAGENAME or error("No Devanagari-script form detected.")
	local scriptCode
	local translit = require("Module:sa-convert").tr
	local m_labels = require("Module:labels")
	
	local terms
	local first
	local output = {[1] = ""}
	local output = Array('<div class="NavFrame" style="max-width:40em"><div class="NavHead" style="background:var(--wikt-palette-lightblue,#d9ebff);color:inherit">Alternative scripts</div><div class="NavContent" style="text-align:left"><ul>')
	for _,script in ipairs(availableScripts) do
		scriptCode = script:getCode()
		terms = { args[scriptCode], args[scriptCode.."2"], args[scriptCode.."3"] }

		if scriptCode ~= "Deva" then
			local auto = translit(devaForm, scriptCode)
			if #terms == 0 then
				terms[1] = auto
			elseif auto == "" then
				-- Helpless - skip script.
			elseif terms[1] ~= auto then
				mw.addWarning("Expected "..auto.." for "..scriptCode.." but given "..terms[1]);
				output:insert("[[Category:Sanskrit terms with inconsistent transliterations]]")
			end
		end
		if terms[1] ~= "" then
			first = true
			for _,term in ipairs(terms) do
				if term ~= nil and term ~= PAGENAME then
					if first then
						first = false
						output:insert("<li>")
					else
						output:insert(" or ")
					end
					output:insert(m_links.full_link({lang = lang, sc = script, term = term, tr = "-"}))
				end
			end
			if not first then
				output:insert(" ")
				output:insert(m_labels.show_labels {
					labels = { script:getDisplayForm() },
					lang = lang
				} .. "</li>")
			end
		end
	end
	output:insert("</ul></div></div>")

	return output:concat()

end

local function add_root_category(args, data, tracking_categories)
	if args[1] then
		table.insert(data.inflections, {label = "root", args[1]})
		if not args.norootcat then
			table.insert(data.categories, "Sanskrit terms belonging to the root " .. args[1])
		end
	end
end

-- The main entry point.
function export.show(frame)
	local tracking_categories = {}
	
	local iparams = {
		[1] = {required = true},
		["def"] = true, -- default value
	}

	local iargs = require("Module:parameters").process(frame.args, iparams)
	local poscat = iargs[1]

	local params = {
		[1] = {},
		["head"] = list,
		["tr"] = {list = true, allow_holes = true},
		["sc"] = {type = "script"},
		["id"] = true,
		["sort"] = true,
		["suff"] = boolean,
	}

	if pos_functions[poscat] then
		for key, val in pairs(pos_functions[poscat].params) do
			params[key] = val
		end
	end
	
    local parargs = frame:getParent().args
	local args = require("Module:parameters").process(parargs, params)
	local heads = args["head"]
	if #heads == 0 and mw.title.getCurrentTitle().nsText == "Template" then
		heads = {iargs["def"]}
	end
	local data = {
		lang = lang,
		sc = args["sc"],
		pos_category = poscat,
		categories = {},
		heads = heads,
		translits = args["tr"],
		genders = {},
		inflections = {},
		id = args["id"],
		sort_key = args["sort"],
		categories = {},
		sccat = true,
	}
	
	if args["suff"] then
		data.pos_category = "suffixes"
		
		if suffix_categories[poscat] then
			local singular_poscat = poscat:gsub("s$", "")
			table.insert(data.categories, langname .. " " .. singular_poscat .. "-forming suffixes")
		else
			error("No category exists for suffixes forming " .. poscat .. ".")
		end
	end
	
	if pos_functions[poscat] then
		pos_functions[poscat].func(args, data, tracking_categories)
	end
	add_root_category(args, data, tracking_categories)
	
	return require("Module:headword").full_headword(data)
		.. require("Module:utilities").format_categories(tracking_categories, lang)
end

pos_functions["verbs"] = {
	params = {
		[2] = true,
		[3] = true,
		[4] = true,
		[5] = true,
		[6] = true,
		[7] = true,
		["norootcat"] = boolean,
	},
	func = function(args, data, tracking_categories)
		local function tooltip(mousetext, anchor, underline)
			return mw.getCurrentFrame():expandTemplate {
				title = "tooltip", args = {mousetext, anchor, und = underline and "1" or nil}
			}
		end
		local function type_to_text(typ)
			return (
				typ == "A" and {"ātmanepada"} or
				typ == "P" and {"parasmaipada"} or
				typ == "U" and {"ubhayapada"} or
				typ == "UP" and {"ubhayapada", "parasmaipada"} or
				typ == "UA" and {"ubhayapada", "ātmanepada"} or
				error("Unrecognized Sanskrit verb type: '" .. typ .. "'; should be one of A, P, U, UP or UA")
			)
		end
		local function type_to_tooltip(typ)
			local desc = table.concat(type_to_text(typ), " — ")
			return tooltip(desc, typ, true)
		end
		local function mode_to_cat(mode)
			if mode == "present" or mode == "causative" or mode == "desiderative" or mode == "intensive" or
				mode == "denominative" then
				return mode .. " verbs"
			elseif mode == "frequentative" then
				return "intensive verbs"
			elseif mode == "passive" then
				return "passive verbs"
			elseif mode == "nominal" then
				return "denominative verbs"
			elseif mode == "perfect" then
				return "perfect verbs"
			elseif mode == "aorist" then
				return "aorist verbs"
			elseif mode == "future" or mode == "periphrastic future" then
				return "future verbs"
			elseif mode == "benedictive" then
				return "benedictive verbs"
			elseif mode == "imperfect" or mode == "conditional" then
				return nil -- FIXME: What about these verbs?
			else
				error("Unrecognized Sanskrit verb mode: '" .. mode .. "'; should be 'present', 'causative', 'desiderative', etc.")
			end
		end

		local function handle_class_type_mode(class, typ, mode, notfirst)
			if class then
				if not class:find("^[1-9]$") and class ~= "10" then
					error("Unrecognized Sanskrit verb class: '" .. class .. "'; should be a number from 1 to 10")
				end
				table.insert(data.inflections, {label = (notfirst and "or " or "") .. "class " .. class})
				table.insert(data.categories, langname .. " class " .. class .. " verbs")
			end
			if typ then
				table.insert(data.inflections, {label = "type " .. type_to_tooltip(typ)})
				for _, desc in ipairs(type_to_text(typ)) do
					table.insert(data.categories, langname .. " " .. desc .. " verbs")
				end
			end
			if mode then
				table.insert(data.inflections, {label = mode})
				local cat = mode_to_cat(mode)
				if cat then
					table.insert(data.categories, langname .. " " .. cat)
				end
			end
		end
		handle_class_type_mode(args[2], args[3], args[4])
		handle_class_type_mode(args[5], args[6], args[7], "notfirst")
		data.gloss = "third-singular indicative"
	end,
}


pos_functions["adjectives"] = {
	params = {
		["comp"] = list, --comparative(s)
		["sup"] = list, --superlative(s)
	},
	func = function(args, data, tracking_categories)
		if args.comp[1] == "-" then
			table.insert(data.inflections, {label = "not comparable"})
			table.insert(data.categories, langname .. " uncomparable adjectives")
		else
			if #args.comp > 0 then
				args.comp.label = glossary_link("comparative")
				args.comp.accel = {form = "comparative"}
				table.insert(data.inflections, args.comp)
			end
		
			if #args.sup > 0 then
				args.sup.label = glossary_link("superlative")
				args.sup.accel = {form = "superlative"}
				table.insert(data.inflections, args.sup)
			end
		end
		data.gloss = "stem"
	end
}

pos_functions["participles"] = {
	params = {
		[2] = true,
		[3] = true,
		[4] = true
	},
	func = function(args, data, tracking_categories)
		local function handle_part_to_type(a1, a2, a3)
			local tense = nil
			local voice = nil
			local typ = {}
			if a1 == "gerundive" then
				tense = "future"
				voice = "passive"
			elseif a1 == "future" or a1 == "fut" then tense = "future"
			elseif a1 == "present" or a1 == "pres" then tense = "present"
			elseif a1 == "perfect" or a1 == "perf" then tense = "perfect"
			elseif a1 == "past" then tense = "past"
			elseif a1 ~= nil then error("unrecognized participle tense " .. a1) end
			
			if a2 == "active" or a2 == "act" or a2 == "a" then voice = "active"
			elseif a2 == "mediopassive" or a2 == "mediopass" or a2 == "mp" then voice = "mediopassive"
			elseif a2 == "passive" or a2 == "pass" or a2 == "p" then voice = "passive"
			elseif a2 ~= nil then error("unrecognized participle voice " .. a2) end
			
			if tense ~= nil then
				table.insert(data.categories, "Sanskrit " ..  tense .. " participles")
				table.insert(typ, tense)
			end
			if voice ~= nil then
				table.insert(data.categories, "Sanskrit " ..  voice .. " participles")
				table.insert(typ, voice)
			end
			if tense ~= nil and voice ~= nil then
				table.insert(data.categories, "Sanskrit " ..  tense .. " " .. voice .. " participles")
			end
			if a3 == "desiderative" or a3 == "desid" then
				table.insert(typ, "desiderative")
			elseif a3 == "intensive" or a3 == "intens" or a3 == "int" or a3 == "frequentive" or a3 == "freq" then
				table.insert(typ, "intensive")
			elseif a3 == "causative" or a3 == "caus" then
				table.insert(typ, "causative")
			elseif a3 ~= nil then error("unrecognized participle " .. a3) end
			if #typ then
				data.gloss = table.concat(typ, " ") .. " participle"
			end
		end
		if args[2] ~= nil then handle_part_to_type(args[2], args[3], args[4]) end
	end
}

local noun_params = {
	["indecl"] = boolean,
	["g"] = list, --gender(s)
	["f"] = list, --feminine form(s)
	["m"] = list, --masculine form(s)
	["n"] = list, --neuter form(s)
}

local allowed_genders = {
	["m"] = true,
	["f"] = true,
	["n"] = true,
	["m-p"] = true,
	["f-p"] = true,
	["n-p"] = true,
	["mf"] = true,
	["mfbysense"] = true,
	["mf-p"] = true,
	["mfbysense-p"] = true,
	["fm"] = true,
	["mn"] = true,
	["nm"] = true,
}

local function do_nouns(plpos, args, data, tracking_categories)
	local genders = {}
	for _, g in ipairs(args.g) do
		if not allowed_genders[g] then
			error("Unrecognized gender: " .. g)
		end
		if g == "fm" then
			table.insert(genders, "f")
			table.insert(genders, "m")
		elseif g == "mn" then
			table.insert(genders, "m")
			table.insert(genders, "n")
		elseif g == "nm" then
			table.insert(genders, "n")
			table.insert(genders, "m")
		else
			-- mf, mfbysense handled internally by [[Module:gender and number]]
			table.insert(genders, g)
		end
	end

	if #genders > 0 then
		data.genders = genders
	else
		data.genders = {"?"}
	end

	if args.indecl then
		table.insert(data.inflections, {label = "indeclinable"})
	end

	if #args.m > 0 then
		args.m.label = "masculine"
		table.insert(data.inflections, args.m)
	end

	if #args.f > 0 then
		args.f.label = "feminine"
		table.insert(data.inflections, args.f)
	end

	if #args.n > 0 then
		args.n.label = "neuter"
		table.insert(data.inflections, args.n)
	end

	data.gloss = "stem"
end

pos_functions["nouns"] = {
	params = noun_params,
	func = function(args, data, tracking_categories)
		return do_nouns("nouns", args, data, tracking_categories)
	end,
}

pos_functions["proper nouns"] = {
	params = noun_params,
	func = function(args, data, tracking_categories)
		return do_nouns("proper nouns", args, data, tracking_categories)
	end,
}

local function pos_with_gender()
	return {
		params = {
			["g"] = list,
		},
		func = function(args, data)
			data.genders = args["g"]
		end,
	}
end

pos_functions.numerals = pos_with_gender()
pos_functions.pronouns = pos_with_gender()
pos_functions.suffixes = pos_with_gender()
pos_functions["adjective forms"] = pos_with_gender()
pos_functions["noun forms"] = pos_with_gender()
pos_functions["proper noun forms"] = pos_with_gender()
pos_functions["pronoun forms"] = pos_with_gender()
pos_functions["determiner forms"] = pos_with_gender()
pos_functions["verb forms"] = pos_with_gender()

return export