Modul:fr-headword

Daripada Wiktionary

Pendokumenan untuk modul ini boleh diciptakan di Modul:fr-headword/doc

local export = {}
local pos_functions = {}
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsubn = mw.ustring.gsub
local rsplit = mw.text.split

local lang = require("Module:languages").getByCode("fr")
		
local suffix_categories = {
	["kata sifat"] = true,
	["kata keterangan"] = true,
	["kata nama" ] = true,
	["kata kerja"] = true,
	["frasa kata depan"] = true,
}

-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
	local retval = rsubn(term, foo, bar)
	return retval
end

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

-- mw.title.new() returns nil if there are weird chars in
-- the pagename.
local function exists(pagename)
	local title = mw.title.new(pagename)
	return title and title.exists
end

local function add_suffix(list, suffix)
	local newlist = {}
	for _, item in ipairs(list) do
		local form
		if suffix == "s" then
			if rfind(item, "[sx]$") then
				form = item
			elseif rfind(item, "al$") then
				form = rsub(item, "al$", "aux")
			else
				form = item .. suffix
			end
		elseif suffix == "e" then
			if rfind(item, "e$") then
				form = item
			elseif rfind(item, "en$") then
				form = item .. "ne"
			elseif rfind(item, "er$") then
				form = rsub(item, "er$", "ère")
			elseif rfind(item, "el$") then
				form = item .. "le"
			elseif rfind(item, "et$") then
				form = item .. "te"
			elseif rfind(item, "on$") then
				form = item .. "ne"
			elseif rfind(item, "ieur$") then
				form = item .. "e"
			elseif rfind(item, "teur$") then
				form = rsub(item, "teur$", "trice")
			elseif rfind(item, "eu[rx]$") then
				form = rsub(item, "eu[rx]$", "euse")
			elseif rfind(item, "if$") then
				form = rsub(item, "if$", "ive")
			elseif rfind(item, "c$") then
				form = rsub(item, "c$", "que")
			else
				form = item .. suffix
			end
		else
			form = item .. suffix
		end
		table.insert(newlist, form)
	end
	return newlist
end

local no_split_words = {
	["c'est"] = true,
	["quelqu'un"] = true,
	["aujourd'hui"] = true,
}

-- Auto-add links to a "space word" (after splitting on spaces). We split off
-- final punctuation, and then split on hyphens if split_dash is given, and
-- also split on apostrophes, including the apostrophe in the link to its left
-- (so we auto-split "l'eau" as "[[l']][[eau]]).
local function add_space_word_links(space_word, split_dash)
	local space_word_no_punct, punct = rmatch(space_word, "^(.*)([,;:?!])$")
	space_word_no_punct = space_word_no_punct or space_word
	punct = punct or ""
	local words
	-- don't split prefixes and suffixes
	if not split_dash or rfind(space_word_no_punct, "^%-") or rfind(space_word_no_punct, "%-$") then
		words = {space_word_no_punct}
	else
		words = rsplit(space_word_no_punct, "%-")
	end
	local linked_words = {}
	for _, word in ipairs(words) do
		if not no_split_words[word] and rfind(word, "'") then
			word = rsub(word, "([^']+')", "[[%1]]")
			word = rsub(word, "%]([^%[%]]*)$", "][[%1]]")
		else
			word = "[[" .. word .. "]]"
		end
		table.insert(linked_words, word)
	end
	return table.concat(linked_words, "-") .. punct
end

-- Auto-add links to a lemma. We split on spaces, and also on hyphens
-- if split_dash is given or the word has no spaces. In addition, we split
-- on apostrophes, including the apostrophe in the link to its left
-- (so we auto-split "de l'eau" as "[[de]] [[l']][[eau]]"). We don't always
-- split on hyphens because of cases like "boire du petit-lait" where
-- "petit-lait" should be linked as a whole, but provide the option to do it
-- for cases like "croyez-le ou non". If there's no space, however, then
-- it makes sense to split on hyphens by default (e.g. for "avant-avant-hier").
-- Cases where only some of the hyphens should be split can always be handled
-- by explicitly specifying the head (e.g. "Nord-Pas-de-Calais").
local function add_lemma_links(lemma, split_dash)
	if not rfind(lemma, " ") then
		split_dash = true
	end
	local words = rsplit(lemma, " ")
	local linked_words = {}
	for _, word in ipairs(words) do
		table.insert(linked_words, add_space_word_links(word, split_dash))
	end
	local retval = table.concat(linked_words, " ")
	-- If we ended up with a single link consisting of the entire lemma,
	-- remove the link.
	local unlinked_retval = rmatch(retval, "^%[%[([^%[%]]*)%]%]$")
	return unlinked_retval or retval
end

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local PAGENAME = mw.title.getCurrentTitle().text
	
	local poscat = frame.args[1] or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
	
	local params = {
		["head"] = {list = true},
		["suff"] = {type = "boolean"},
		["splitdash"] = {type = "boolean"},
	}

	if rfind(PAGENAME, " ") then
		track("space")
	end

	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 pos_functions[poscat] and pos_functions[poscat].param1_is_head and args[1] then
		-- FIXME! REMOVE ME! Hack to correspond to previous template code in {{fr-adv}}.
		if args[1] == "-" then
			track("arg1dash")
		else
			table.insert(heads, 1, args[1])
		end
	end
	local auto_linked_head = add_lemma_links(PAGENAME, args["splitdash"])
	if #heads == 0 then
		heads = {auto_linked_head}
	else
		for _, head in ipairs(heads) do
			if head == auto_linked_head then
				track("redundant-head")
			end
		end
	end
		
	local data = {lang = lang, pos_category = poscat, categories = {}, heads = heads, genders = {}, inflections = {}, categories = {}}
	
	if args["suff"] then
		data.pos_category = "akhiran"
		
		if suffix_categories[poscat] then
			local singular_poscat = poscat:gsub("s$", "")
			table.insert(data.categories, "Bahasa " .. lang:getCanonicalName() .. " akhiran bentuk " .. singular_poscat)
		else
			error("No category exists for suffixes forming " .. poscat .. ".")
		end
	end
	
	if pos_functions[poscat] then
		pos_functions[poscat].func(args, data)
	end
	
	return require("Module:headword").full_headword(data)
end

local allowed_genders = {
	["m"] = true,
	["f"] = true,
	["m-p"] = true,
	["f-p"] = true,
	["m-s"] = true,
	["f-s"] = true,
}

local function get_noun_pos(is_proper)
	return {
		params = {
			[1] = {},
			["g"] = {list = true},
			[2] = {list = true},
			["f"] = {list = true},
			["m"] = {list = true},
			["dim"] = {list = true},
			},
		func = function(args, data)
			local PAGENAME = mw.title.getCurrentTitle().text
			
			local function default_plural()
				if rfind(PAGENAME, 'x$') then
					track("default-x")
				end
				if rfind(PAGENAME, 'z$') then
					track("default-z")
				end
				if rfind(PAGENAME, '[sxz]$') then
					return PAGENAME
				elseif rfind(PAGENAME, '[ae]u$') then
					return "x"
				elseif rfind(PAGENAME, 'al$') then
					return mw.ustring.sub(PAGENAME, 1, -3) .. 'aux'
				else
					return "s"
				end
			end

			-- Gather genders
			local function insert_gender(g)
				if g == "mf" then
					table.insert(data.genders, "m")
					table.insert(data.genders, "f")
				else
					table.insert(data.genders, g)
				end
			end
			insert_gender(args[1])
			for _, g in ipairs(args.g) do
				insert_gender(g)
			end

			-- Gather all the plural parameters from the numbered parameters.
			local plurals = args[2]
			plurals.label = "jamak"
			plurals.accel = {form = "p"}
			plurals.request = true
			
			-- Gather all the feminine parameters
			local feminines = args["f"]
			feminines.label = "feminin"
			
			-- Gather all the masculine parameters
			local masculines = args["m"]
			masculines.label = "maskulin"
			
			-- Add categories for genders
			if #data.genders == 0 then
				table.insert(data.genders, "?")
			end
			
			local mode = nil
			
			for _, g in ipairs(data.genders) do
				if g == "m-p" or g == "f-p" then
					mode = "p"
				end

				if g == "?" and (is_proper or mw.title.getCurrentTitle().nsText == "Templat") then
					-- allow unknown gender in template example and proper nouns,
					-- since there are currently so many proper nouns with
					-- unspecified gender
				elseif g and g ~= "" and not allowed_genders[g] then
					error("Unrecognized French gender: " .. g)
				end

				if g == "m" or g == "m-p" or g == "m-s" then
					table.insert(data.categories, "Kata nama maskulin bahasa Perancis")
				elseif g == "f" or g == "f-p" or g == "f-s" then
					table.insert(data.categories, "Kata nama feminin bahasa Perancis")
				end
			end
			
			-- Decide how to show the plurals
			mode = mode or plurals[1]
			
			-- Plural is not attested
			if mode == "!" then
				table.insert(data.inflections, {label = "jamak tidak dibuktikan"})
				table.insert(data.categories, "Kata nama bahasa Perancis dengan jamak tidak dibuktikan")
			-- Plural-only noun, doesn't have a plural
			elseif mode == "p" then
				table.insert(data.inflections, {label = "jamak sahaja"})
				table.insert(data.categories, "Pluralia tantum bahasa Perancis")
			else
				-- Plural is unknown
				if mode == "?" then
					table.remove(plurals, 1)  -- Remove the mode parameter
				-- Uncountable noun; may occasionally have a plural
				elseif mode == "-" then
					table.remove(plurals, 1)  -- Remove the mode parameter
					table.insert(data.categories, "Kata nama tiak berbilang bahasa Perancis")
				
					-- If plural forms were given explicitly, then show "usually"
					if #plurals > 0 then
						track("count-uncount")
						table.insert(data.inflections, {label = "biasanya [[Lampiran:Glosari#berbilang|berbilang]]"})
						table.insert(data.categories, "Kata nama bahasa Perancis berbilang")
					else
						table.insert(data.inflections, {label = "[[Lampiran:Glosari#tidak berbilang|tidak berbilang]]"})
					end
				-- Mixed countable/uncountable noun, always has a plural
				elseif mode == "~" then
					table.remove(plurals, 1)  -- Remove the mode parameter
					table.insert(data.inflections, {label = "[[Lampiran:Glosari#berbilang|berbilang]] dan [[Lampiran:Glosari#tidak berbilang|tidak berbilang]]"})
					table.insert(data.categories, "Kata nama tidak berbilang bahasa Perancis")
					table.insert(data.categories, "Kata nama berbilang bahasa Perancis")
				
					-- If no plural was given, add a default one now
					if #plurals == 0 then
						table.insert(plurals, default_plural())
					end
				-- Default proper noun; uncountable unless plural(s) specified
				elseif is_proper then
					if #plurals > 0 then
						table.insert(data.categories, "Kata nama berbilang bahasa Perancis")
					else
						table.insert(data.categories, "Kata nama tidak berbilang bahasa Perancis")
					end
				-- The default, always has a plural
				else
					table.insert(data.categories, "Kata nama berbilang bahasa Perancis")
					
					-- If no plural was given, add a default one now
					if #plurals == 0 then
						table.insert(plurals, default_plural())
					end
				end
				
				-- Process the plural forms
				for i, pl in ipairs(plurals) do
					if pl == "*" then
						pl = PAGENAME
					elseif pl == "s" then
						pl = PAGENAME .. "s"
					elseif pl == "x" then
						pl = PAGENAME .. "x"
					end

					if not exists(pl) then
						table.insert(data.categories, "Kata nama bahasa Perancis dengan jamak yang hilang")
					end
					
					plurals[i] = pl
				end
		
				-- Add the plural forms; do this in some cases even if no plurals
				-- specified so we get a "please provide plural" message.
				if mode ~= "-" and (not is_proper or mode) or #plurals > 0 then
					table.insert(data.inflections, plurals)
				end
			end
			
			-- Add the feminine forms
			if #feminines > 0 then
				table.insert(data.inflections, feminines)
				
				for _, f in ipairs(feminines) do
					if not exists(f) then
						table.insert(data.categories, "Kata nama bahasa Perancis dengan bentuk yang hilang")
					end
				end
			end
			
			-- Add the masculine forms
			if #masculines > 0 then
				table.insert(data.inflections, masculines)
				
				for _, m in ipairs(masculines) do
					if not exists(m) then
						table.insert(data.categories, "Kata nama bahasa Perancis dengan bentuk yang hilang")
					end
				end
			end

			-- Handle diminutives
			if #args.dim > 0 then
				local dims_infl = mw.clone(args.dim)
				dims_infl.label = "diminutif"
				dims_infl.accel = {form = "diminutif"}
				table.insert(data.inflections, dims_infl)
			end
		end
	}
end

pos_functions["kata nama"] = get_noun_pos(false)

pos_functions["kata nama khas"] = get_noun_pos(true)

pos_functions["kata ganti nama"] = {
	params = {
		["head"] = {list = true},
		[1] = {alias_of = "g"},
		["g"] = {list = true},
		["f"] = {list = true},
		["fqual"] = {list = true, allow_holes = true},
		["m"] = {list = true},
		["mqual"] = {list = true, allow_holes = true},
		["fp"] = {list = true},
		["fpqual"] = {list = true, allow_holes = true},
		["mp"] = {list = true},
		["mpqual"] = {list = true, allow_holes = true},
		["p"] = {list = true},
		["pqual"] = {list = true, allow_holes = true},
		},
	func = function(args, data)
		local PAGENAME = mw.title.getCurrentTitle().text
		
		-- Gather genders
		local function insert_gender(g)
			if g == "mf" then
				table.insert(data.genders, "m")
				table.insert(data.genders, "f")
			else
				table.insert(data.genders, g)
			end
		end
		for _, g in ipairs(args.g) do
			insert_gender(g)
		end

		local function process_inflection(label, infls, quals)
			infls.label = label
			for i, infl in ipairs(infls) do
				if quals[i] then
					infls[i] = {term = infl, qualifiers = {quals[i]}}
				end
			end
		end

		-- Gather all inflections.
		process_inflection("maskulin", args["m"], args["mqual"])			
		process_inflection("feminin", args["f"], args["fqual"])			
		process_inflection("jamak maskulin", args["mp"], args["mpqual"])			
		process_inflection("jamak feminin", args["fp"], args["fpqual"])			
		process_inflection("jamak", args["p"], args["pqual"])			

		-- Add categories for genders
		if #data.genders == 0 then
			table.insert(data.genders, "?")
		end

		-- Validate/canonicalize genders			
		for i, g in ipairs(data.genders) do
			if g == "m." then
				data.genders[i] = "m"
			elseif g == "f." then
				data.genders[i] = "f"
			elseif g == "?" and mw.title.getCurrentTitle().nsText == "Templat" then
				-- allow unknown gender in template example
			elseif g == "?" then
				-- FIXME, remove this branch once we've added the required genders
				track("missing-pron-gender")
			elseif g and g ~= "" and not allowed_genders[g] then
				error("Unrecognized French gender: " .. g)
			end
		end

		-- Add the inflections
		if #args["m"] > 0 then
			table.insert(data.inflections, args["m"])
		end
		if #args["f"] > 0 then
			table.insert(data.inflections, args["f"])
		end
		if #args["mp"] > 0 then
			table.insert(data.inflections, args["mp"])
		end
		if #args["fp"] > 0 then
			table.insert(data.inflections, args["fp"])
		end
		if #args["p"] > 0 then
			table.insert(data.inflections, args["p"])
		end
	end
}


local function get_misc_pos()
	return {
		param1_is_head = true,
		params = {
			[1] = {},
		},
		func = function(args, data)
		end
	}
end

pos_functions["kata keterangan"] = get_misc_pos()
	
pos_functions["kata depan"] = get_misc_pos()

pos_functions["frasa"] = get_misc_pos()

pos_functions["frasa kata depan"] = get_misc_pos()

pos_functions["simpulan bahasa"] = get_misc_pos()

pos_functions["tanda baca"] = get_misc_pos()

pos_functions["tanda diakritik"] = get_misc_pos()

pos_functions["kata seru"] = get_misc_pos()

pos_functions["awalan"] = get_misc_pos()

pos_functions["penyingkatan"] = get_misc_pos()

pos_functions["kata sifat"] = {
	params = {
		[1] = {},
		["inv"] = {},
		["m2"] = {},
		["onlyg"] = {},
		["f"] = {list = true},
		["mp"] = {list = true},
		["fp"] = {list = true},
		["p"] = {list = true},
		["current"] = {list = true},
		["comp"] = {list = true},
		["sup"] = {list = true},
		},
	func = function(args, data)
		local PAGENAME = mw.title.getCurrentTitle().text
		if args.onlyg == "p" or args.onlyg == "m-p" or args.onlyg == "f-p" then
			table.insert(data.categories, "Pluralia tantum bahasa Perancis")
		end
		if args.onlyg == "s" or args.onlyg == "f-s" or args.onlyg == "f-s" then
			table.insert(data.categories, "Singularia tantum bahasa Perancis")
		end
		if args.onlyg then
			table.insert(data.categories, "Kata sifat cangga bahasa Perancis")
		end
		if args.onlyg == "p" then
			table.insert(data.inflections, {label = "jamak sahaja"})
			if args[1] ~= "mf" then
				-- Handle feminine plurals
				if #args.fp > 0 then
					local fplurals_infl = mw.clone(args.fp)
					fplurals_infl.label = "jamak feminin"
					fplurals_infl.accel = {form = "f|p"}
					table.insert(data.inflections, fplurals_infl)
				end
			end
		elseif args.onlyg == "s" then
			table.insert(data.inflections, {label = "mufrad sahaja"})
			if not (args[1] == "mf" or #args.f == 0 and rfind(PAGENAME, "e$")) then
				-- Handle feminines
				local feminines = #args.f > 0 and args.f or add_suffix(#args.current > 0 and args.current or {PAGENAME}, "e")
				local feminines_infl = mw.clone(feminines)
				feminines_infl.label = "mufrad feminin"
				feminines_infl.accel = {form = "f|s"}
				table.insert(data.inflections, feminines_infl)
			end
		elseif args.onlyg == "m" then
			table.insert(data.genders, "m")
			table.insert(data.inflections, {label = "maskulin sahaja"})
			-- Handle masculine plurals
			local mplurals = #args.mp > 0 and args.mp or add_suffix(#args.current > 0 and args.current or {PAGENAME}, "s")
			local mplurals_infl = mw.clone(mplurals)
			mplurals_infl.label = "jamak maskulin"
			mplurals_infl.accel = {form = "m|p"}
			table.insert(data.inflections, mplurals_infl)
		elseif args.onlyg == "f" then
			table.insert(data.genders, "f")
			table.insert(data.inflections, {label = "feminin sahaja"})
			-- Handle feminine plurals
			local fplurals = #args.fp > 0 and args.fp or add_suffix(#args.current > 0 and args.current or {PAGENAME}, "s")
			local fplurals_infl = mw.clone(fplurals)
			fplurals_infl.label = "jamak feminin"
			fplurals_infl.accel = {form = "f|p"}
			table.insert(data.inflections, fplurals_infl)
		elseif args.onlyg then
			table.insert(data.genders, args.onlyg)
			table.insert(data.inflections, {label = "cangga"})
		else
			-- Gather genders
			local gender = args[1]
			-- Default to mf if base form ends in -e and no feminine,
			-- feminine plural or gender specified
			if not gender and #args.f == 0 and #args.fp == 0 and rfind(PAGENAME, "e$") then
				gender = "mf"
			end
			
			if #args.current > 0 then
				track("adj-current")
			end
			
			if args.inv then
				table.insert(data.inflections, {label = "kata tetap bentuk"})
			end
			
			-- Handle plurals of mf adjectives
			local plurals = #args.p > 0 and args.p or {PAGENAME .. "s"}
			if not args.inv and gender == "mf" then
				local plurals_infl = mw.clone(plurals)
				plurals_infl.label = "jamak"
				plurals_infl.accel = {form = "p"}
				table.insert(data.inflections, plurals_infl)
			end
			
			if not args.inv and gender ~= "mf" then
				-- Handle case of special masculine singular before vowel
				if args.m2 then
					local masc_before_vowel = {args.m2}
					masc_before_vowel.label = "mufrad maskulin sebelum vokal"
					masc_before_vowel.accel = {form = "m|s"}
					table.insert(data.inflections, masc_before_vowel)
				end
				
				-- Handle feminines
				local feminines = #args.f > 0 and args.f or add_suffix(#args.current > 0 and args.current or {PAGENAME}, "e")
				local feminines_infl = mw.clone(feminines)
				feminines_infl.label = "mufrad feminin"
				feminines_infl.accel = {form = "f|s"}
				table.insert(data.inflections, feminines_infl)
				
				-- Handle masculine plurals
				local mplurals = #args.mp > 0 and args.mp or add_suffix(#args.current > 0 and args.current or {PAGENAME}, "s")
				local mplurals_infl = mw.clone(mplurals)
				mplurals_infl.label = "jamak maskulin"
				mplurals_infl.accel = {form = "m|p"}
				table.insert(data.inflections, mplurals_infl)
				
				-- Handle feminine plurals
				local fplurals = #args.fp > 0 and args.fp or add_suffix(feminines, "s")
				local fplurals_infl = mw.clone(fplurals)
				fplurals_infl.label = "jamak feminin"
				fplurals_infl.accel = {form = "f|p"}
				table.insert(data.inflections, fplurals_infl)
			end
		end
		
		-- Handle comparatives
		if #args.comp > 0 then
			local comps_infl = mw.clone(args.comp)
			comps_infl.label = "perbandingan"
			comps_infl.accel = {form = "perbandingan"}
			table.insert(data.inflections, comps_infl)
		end
		
		-- Handle superlatives
		if #args.sup > 0 then
			local sups_infl = mw.clone(args.sup)
			sups_infl.label = "superlatif"
			sups_infl.accel = {form = "superlatif"}
			table.insert(data.inflections, sups_infl)
		end
		
		-- Check existence
		for key, val in pairs(data.inflections) do
			for i, form in ipairs(val) do
				if not exists(form) then
					table.insert(data.categories, "Kata sifat bahasa Perancis dengan bentuk yang hilang")
					return
				end
			end
		end
	end
}

pos_functions["kata kerja"] = {
	param1_is_head = true,
	params = {
		[1] = {},
		["type"] = {list = true},
	},
	func = function(args, data)
		local PAGENAME = mw.title.getCurrentTitle().text
		for _, ty in ipairs(args.type) do
			local category, label
			if ty == "auxiliary" then
				category = "kata kerja bantu"
			elseif ty == "cangga" then
				category = "kata kerja cangga"
				label = "[[cangga]]"
			elseif ty == "impersonal" then
				category = "kata kerja impersonal"
				label = "[[impersonal]]"
			elseif ty == "modal" then
				category = "kata kerja modal"
			elseif ty == "kata refleksif" then
				category = "kata kerja refleksif "
			elseif ty == "transitif" then
				label = "[[transitif]]"
			elseif ty == "intransitif" then
				label = "[[intransitif]]"
			elseif ty == "ambitransitif" or ty == "ambi" then
				label = "[[transitif]] dan [[intransitif]]"
			end
			if category then
				table.insert(data.categories, category .. " bahasa Perancis")
			end
			if label then
				table.insert(data.inflections, {label = label})
			end
		end
	end
}

return export

-- For Vim, so we get 4-space tabs
-- vim: set ts=4 sw=4 noet: