Module:sa-decl

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.

...

To indicate that a word ending on -vat/-mat is to be declined as a present participle (not as suffixed with -vat/-mat), use "participle=1"
Use "at_nom_s=1" for participles like जुह्वत् (júhvat) (or a case like वाघत् (vāghát)) with nom.s. 'júhvat', acc.s. 'júhvatam', etc.

...


local export = {}

local m_para = require("Module:parameters")
local m_links = require("Module:links")
local m_utils = require("Module:utilities")
local lang = require("Module:languages").getByCode("sa")
local m_script_utils = require("Module:script utilities")
local sa_decl_data = require("Module:sa-decl/data")
local SLP_to_IAST = require("Module:sa-utilities/translit/SLP1-to-IAST")
local sa_utils_translit = require("Module:sa-utilities/translit")
local PAGENAME = mw.title.getCurrentTitle().text

local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local match = mw.ustring.match
local len = mw.ustring.len

local accent = '[/\\]'

local genders = {
	m = 'Masculine', f = 'Feminine', n = 'Neuter',
}
local cases = {
	{'nom', 'Nominative'}, {'voc', 'Vocative'}, {'acc', 'Accusative'}, {'ins', 'Instrumental'},
	{'dat', 'Dative'}, {'abl', 'Ablative'}, {'gen', 'Genitive'}, {'loc', 'Locative'},
}

local super_nums = {
	[1] = '¹', [2] = '²', [3] = '³', [4] = '⁴', [5] = '⁵',
	[6] = '⁶', [7] = '⁷', [8] = '⁸', [9] = '⁹', [0] = '⁰',
}

local function to_super(num)
	local annotation = gsub(num, ".", super_nums)
	return annotation
end

local function get_form_note_tags(form_notes, data)
	local output = {}
	if type(form_notes) ~= 'table' then form_notes = { form_notes } end
	for _, form_note in ipairs(form_notes) do
		if type(data.form_notes[form_note]) ~= "number" then
			table.insert(data.form_notes_out, form_note)
			data.form_notes[form_note] = #data.form_notes_out
		end
		table.insert(output, to_super(data.form_notes[form_note]))
	end
	return table.concat(output)
end

local function make_header(args, data, sc_cache)
	local width = '40'
	local title = genders[args.g] .. ' ' .. ' ' .. data.decl_type .. ' declension of ' ..
			m_links.full_link({term = nil, alt = sc_cache.reverse_tr(args.lemma), tr = SLP_to_IAST.tr(args.lemma), lang = lang, sc = sc_cache.sc})
	
	local header = {'{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background:#F9F9F9; text-align:center; border: 1px solid #CCC; width: ' .. width .. 'em"\n'}
	table.insert(header, '|- style="background: #d9ebff;"\n')
	table.insert(header, '! class="vsToggleElement" style="text-align: left;" colspan="4" | ' .. title .. '\n')
	table.insert(header, '|- class="vsHide"\n')
	table.insert(header, '! style="background:#eff7ff" |\n')
	
	if args.n == 'sdp' then
		table.insert(header, '! style="background:#eff7ff" | Singular\n')
		table.insert(header, '! style="background:#eff7ff" | Dual\n')
		table.insert(header, '! style="background:#eff7ff" | Plural\n')
	elseif args.n == 's' then
		table.insert(header, '! style="background:#eff7ff" | Singular\n')
	elseif args.n == 'd' then
		table.insert(header, '! style="background:#eff7ff" | Dual\n')
	elseif args.n == 'p' then
		table.insert(header, '! style="background:#eff7ff" | Plural\n')
	end
	return table.concat(header)
end

local function make_cell(args, data, code, num, sc_cache)
	local tag = code .. '_' .. num
	local forms, links, trs = {}, {}, {}
	if args[tag] then
		forms = mw.text.split(sc_cache.tr(args[tag]), '%s*[,]%s*')
	else
		forms = data.forms[tag]
	end

	if not forms then
		error("Internal error: No forms for slot '" .. tag .. "'")
	end
	for i, form in ipairs(forms) do
		if form == "" then -- in case of form reduced to zero by 'novedic' parameter
			-- do nothing
		else
			local form_note_tag = get_form_note_tags(forms['note' .. i] or {}, data)
			-- a superscript number at the end of manually added forms should not be part of the (linked) form
			if match(form, "[¹²³⁴⁵⁶⁷⁸⁹]$") then
				extra_note_tag = gsub(form, "^.+(.)$", "%1")
				form = gsub(form, ".$", "")
			else
				extra_note_tag = ""
			end
			
			if form == "-" then
				table.insert(links, m_links.full_link({term = nil, alt = '-', tr = '-', lang = lang, sc = sc_cache.sc}))
				table.insert(trs, '-')
			else
				table.insert(links, m_links.full_link({ term = sc_cache.reverse_tr(form), tr = '-', lang = lang, sc = sc_cache.sc }) .. 
					form_note_tag .. extra_note_tag)
				table.insert(trs, SLP_to_IAST.tr(form) .. form_note_tag .. extra_note_tag)
			end
		end
	end
	
	return table.concat {
		'| ',
		table.concat(links, ' / '),
		'<br/>',
		m_script_utils.tag_translit(table.concat(trs, ' / '), lang, "default", 'style="color: #888;"'),
		'\n'
	}
end

local function format_notes(args, data)
	local output = {
		'|- class="vsHide"',
		'| style="background-color:#eff7ff; font-style:italic;border-top:double #888;" | Notes',
		'| style="text-align:left;border-top:double #888;" colspan=' .. len(args.n) .. ' |'
	}
	if #data.form_notes_out > 0 or #data.general_notes > 0 or #args.note > 0 then
		for i, form_note in ipairs(data.form_notes_out) do
			table.insert(output, '* ' .. to_super(i) .. form_note)
		end
		for _, general_note in ipairs(data.general_notes) do
			table.insert(output, '* ' .. general_note)
		end
		for _, note in ipairs(args.note) do
			table.insert(output, '* ' .. note)
		end
		return table.concat(output, '\n') .. '\n'
	else
		return ''
	end
end

local function make_table_noun(args, data, sc_cache)
	local output = {make_header(args, data, sc_cache)}
	for _, case in ipairs(cases) do
		local code, name = case[1], case[2]
		table.insert(output, '|- class="vsHide"\n')
		table.insert(output, '! style="background-color:#eff7ff; font-style:italic;" | ' .. name ..'\n')
		if args.n == 'sdp' then
			table.insert(output, make_cell(args, data, code, 's', sc_cache))
			table.insert(output, make_cell(args, data, code, 'd', sc_cache))
			table.insert(output, make_cell(args, data, code, 'p', sc_cache))
		elseif args.n == 's' then
			table.insert(output, make_cell(args, data, code, 's', sc_cache))
		elseif args.n == 'd' then
			table.insert(output, make_cell(args, data, code, 'd', sc_cache))
		elseif args.n == 'p' then
			table.insert(output, make_cell(args, data, code, 'p', sc_cache))
		end
	end
	table.insert(output, format_notes(args, data))
	table.insert(output, '|}')
	if not args.nocat and #data.categories > 0 then
		table.insert(output, m_utils.format_categories(data.categories, lang))
	end
	return table.concat(output)
end

local function get_sc_details(args)
	local sc, scCode
	if args.sc then
		sc = require("Module:scripts").getByCode(args.sc)
		scCode = args.sc
	else
		sc = lang:findBestScript(args.lemma)
		scCode = sc:getCode()
		if scCode == 'None' then
			sc = lang:findBestScript(PAGENAME)
			scCode = sc:getCode()
			if scCode == 'None' then
				error('Script code was not specified or detected.')
			end
		end
	end
	
	local tr, reverse_tr = sa_utils_translit.retrieve_tr_modules(scCode)
	return { tr = tr, reverse_tr = reverse_tr, sc = sc, scCode = scCode}
end

function export.show(frame)
	local params = {
		lemma = {default = PAGENAME},
		decl = {default = nil},
		n = {default = 'sdp'},
		sc = {},
		[1] = {alias_of = 'lemma'},
		nom_s = {}, nom_d = {}, nom_p = {},
		acc_s = {}, acc_d = {}, acc_p = {},
		ins_s = {}, ins_d = {}, ins_p = {},
		dat_s = {}, dat_d = {}, dat_p = {},
		abl_s = {}, abl_d = {}, abl_p = {},
		gen_s = {}, gen_d = {}, gen_p = {},
		loc_s = {}, loc_d = {}, loc_p = {},
		voc_s = {}, voc_d = {}, voc_p = {},
		note = { list = true },
		root = { type = 'boolean' }, compound = { type = 'boolean' },
		pronominal = { type = 'boolean' }, -- use pronominal declension, e.g. for 'sarva'
		novedic = {default = false, type = "boolean" }, -- disable extra Vedic forms
		r_stem_a = {},
		at_nom_s = { type = 'boolean' },
		ambig_final = {},    -- for stems on -j, -ś or -h
		diaspirate = { type = 'boolean' },  -- for diaspirate roots like 'duh'
		participle = { type = 'boolean' },
		contract = { type = 'boolean' },
		adj = { type = 'boolean' }, -- internal argument for categorizing adjectives
		nocat = {},
	}
	local data = {
		forms = {},
		categories = {},
		decl_type = nil,
		form_notes = {},
		form_notes_out = {},
		general_notes = {},
	}
	local args = m_para.process(frame:getParent().args, params)
	args.g = frame.args[1]
	if args.pronominal then 
		args.root = false  -- the pronominal endings override the usual declension pattern
	end
	
	local sc_cache = get_sc_details(args)
	
	args.lemma = sc_cache.tr(args.lemma)
	args.has_accent = match(args.lemma, accent)

	if args.decl == nil then
		for decl, decl_data in pairs(sa_decl_data) do
			if decl_data.detect(args) then
				sa_decl_data[decl](args, data)
				break
			end
		end
	end
	if data.decl_type == nil then
		error("No declension class could be detected. Please check the lemma form or specify the declension.")
	end

	return make_table_noun(args, data, sc_cache)
end

return export