Module:fr-headword

Definition from Wiktionary, the free dictionary
Jump to: navigation, search

This module is used for French headword-line templates. This module currently implements {{fr-noun}} and {{fr-adj}}; see the documentation of those templates for more information.

The module is always invoked the same way, by passing a single parameter to the "show" function. This parameter is the name of the part of speech, but in plural (examples given are for nouns, and for adjective forms respectively):

{{#invoke:fr-headword|show|nouns}}
{{#invoke:fr-headword|show|adjective forms}}

The template will, by default, accept the following parameters (specific parts of speech may accept or require others):

|head=
Override the headword display, used to add links to individual words in a multi-word term.

There is no parameter for the sort key, because this is not necessary. The sort key is automatically generated according to the normal alphabetical ordering in French.


local export = {}
local pos_functions = {}
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub

local lang = require("Module:languages").getByCode("fr")
		
local suffix_categories = {
	["adjectives"] = true,
	["adverbs"] = true,
	["nouns"] = true,
	["verbs"] = 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

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

-- 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, default = ""},
		["suff"] = {type = "boolean"},
	}

	if mw.ustring.find(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 data = {lang = lang, pos_category = poscat, categories = {}, heads = args["head"], genders = {}, inflections = {}, categories = {}}
	
	if args["suff"] then
		data.pos_category = "suffixes"
		
		if suffix_categories[poscat] then
			local singular_poscat = poscat:gsub("s$", "")
			table.insert(data.categories, lang:getCanonicalName() .. " " .. 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)
	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,
}

pos_functions["nouns"] = {
	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 mw.ustring.find(PAGENAME, 'x$') then
				track("default-x")
			end
			if mw.ustring.find(PAGENAME, 'z$') then
				track("default-z")
			end
			if mw.ustring.find(PAGENAME,'[sxz]$') then
				return PAGENAME
			elseif mw.ustring.find(PAGENAME,'[ae]u$') then
				return "x"
			elseif mw.ustring.find(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 = "plural"
		plurals.accel = "plural-form-of"
		plurals.request = true
		
		-- Gather all the feminine parameters
		local feminines = args["f"]
		feminines.label = "feminine"
		
		-- Gather all the masculine parameters
		local masculines = args["m"]
		masculines.label = "masculine"
		
		-- 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 mw.title.getCurrentTitle().nsText == "Template" then
				-- allow unknown gender in template example
			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, "French masculine nouns")
			elseif g == "f" or g == "f-p" or g == "f-s" then
				table.insert(data.categories, "French feminine nouns")
			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 = "plural not attested"})
			table.insert(data.categories, "French nouns with unattested plurals")
		-- Plural-only noun, doesn't have a plural
		elseif mode == "p" then
			table.insert(data.inflections, {label = "plural only"})
			table.insert(data.categories, "French pluralia tantum")
		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, "French uncountable nouns")
			
				-- If plural forms were given explicitly, then show "usually"
				if #plurals > 0 then
					track("count-uncount")
					table.insert(data.inflections, {label = "usually [[Appendix:Glossary#uncountable|uncountable]]"})
					table.insert(data.categories, "French countable nouns")
				else
					table.insert(data.inflections, {label = "[[Appendix:Glossary#uncountable|uncountable]]"})
				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 = "[[Appendix:Glossary#countable|countable]] and [[Appendix:Glossary#uncountable|uncountable]]"})
				table.insert(data.categories, "French uncountable nouns")
				table.insert(data.categories, "French countable nouns")
			
				-- If no plural was given, add a default one now
				if #plurals == 0 then
					table.insert(plurals, default_plural())
				end
			-- The default, always has a plural
			else
				table.insert(data.categories, "French countable nouns")
				
				-- 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

				-- mw.title.new() can return nil if there are weird chars in
				-- the plural
				local newtitle = mw.title.new(pl)
				if newtitle and not newtitle.exists then
					table.insert(data.categories, "French nouns with missing plurals")
				end
				
				plurals[i] = pl
			end
	
			-- Add the plural forms
			if 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 mw.title.new(f).exists then
					table.insert(data.categories, "French nouns with missing forms")
				end
			end
		end
		
		-- Add the masculine forms
		if #masculines > 0 then
			table.insert(data.inflections, masculines)
			
			for _, m in ipairs(masculines) do
				if not mw.title.new(m).exists then
					table.insert(data.categories, "French nouns with missing forms")
				end
			end
		end

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

pos_functions["adjectives"] = {
	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, "French pluralia tantum")
		end
		if args.onlyg == "s" or args.onlyg == "f-s" or args.onlyg == "f-s" then
			table.insert(data.categories, "French singularia tantum")
		end
		if args.onlyg then
			table.insert(data.categories, "French defective adjectives")
		end
		if args.onlyg == "p" then
			table.insert(data.inflections, {label = "plural only"})
			if args[1] ~= "mf" then
				-- Handle feminine plurals
				if #args.fp > 0 then
					local fplurals_infl = mw.clone(args.fp)
					fplurals_infl.label = "feminine plural"
					fplurals_infl.accel = "feminine-plural-form-of"
					table.insert(data.inflections, fplurals_infl)
				end
			end
		elseif args.onlyg == "s" then
			table.insert(data.inflections, {label = "singular only"})
			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 = "feminine singular"
				feminines_infl.accel = "feminine-singular-form-of"
				table.insert(data.inflections, feminines_infl)
			end
		elseif args.onlyg == "m" then
			table.insert(data.genders, "m")
			table.insert(data.inflections, {label = "masculine only"})
			-- 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 = "masculine plural"
			mplurals_infl.accel = "masculine-plural-form-of"
			table.insert(data.inflections, mplurals_infl)
		elseif args.onlyg == "f" then
			table.insert(data.genders, "f")
			table.insert(data.inflections, {label = "feminine only"})
			-- 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 = "feminine plural"
			fplurals_infl.accel = "feminine-plural-form-of"
			table.insert(data.inflections, fplurals_infl)
		elseif args.onlyg then
			table.insert(data.genders, args.onlyg)
			table.insert(data.inflections, {label = "defective"})
		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 = "invariable"})
			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 = "plural"
				plurals_infl.accel = "plural-form-of"
				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 = "masculine singular before vowel"
					masc_before_vowel.accel = "masculine-singular-form-of"
					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 = "feminine singular"
				feminines_infl.accel = "feminine-singular-form-of"
				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 = "masculine plural"
				mplurals_infl.accel = "masculine-plural-form-of"
				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 = "feminine plural"
				fplurals_infl.accel = "feminine-plural-form-of"
				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 = "comparative"
			comps_infl.accel = "comparative-form-of"
			table.insert(data.inflections, comps_infl)
		end
		
		-- Handle superlatives
		if #args.sup > 0 then
			local sups_infl = mw.clone(args.sup)
			sups_infl.label = "superlative"
			sups_infl.accel = "superlative-form-of"
			table.insert(data.inflections, sups_infl)
		end
	end
}

return export