Module:fr-headword: difference between revisions

From Wiktionary, the free dictionary
Jump to navigation Jump to search
Content deleted Content added
No edit summary
should negate it after calling it
Line 24: Line 24:
end
end


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


Line 272: Line 272:
end
end


if exists(pl) then
if not exists(pl) then
table.insert(data.categories, "French nouns with missing plurals")
table.insert(data.categories, "French nouns with missing plurals")
end
end
Line 290: Line 290:
for _, f in ipairs(feminines) do
for _, f in ipairs(feminines) do
if exists(f) then
if not exists(f) then
table.insert(data.categories, "French nouns with missing forms")
table.insert(data.categories, "French nouns with missing forms")
end
end
Line 301: Line 301:
for _, m in ipairs(masculines) do
for _, m in ipairs(masculines) do
if exists(m) then
if not exists(m) then
table.insert(data.categories, "French nouns with missing forms")
table.insert(data.categories, "French nouns with missing forms")
end
end
Line 461: Line 461:
for key, val in pairs(data.inflections) do
for key, val in pairs(data.inflections) do
for i, form in ipairs(val) do
for i, form in ipairs(val) do
if exists(form) then
if not exists(form) then
table.insert(data.categories, "French adjectives with missing forms")
table.insert(data.categories, "French adjectives with missing forms")
return
return

Revision as of 19:34, 31 August 2017


This module is used for French headword-line templates. This module currently implements {{fr-noun}}, {{fr-verb}}, {{fr-adj}}, {{fr-adv}}, {{fr-intj}}, {{fr-phrase}} and several others; 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 multiword term.
|nolinkhead=1
Don't link individual words in the headword of a multiword term. Useful for foreign terms like a posteriori and top model where the expression functions as a whole in French but the individual parts are not French words.
|splithyph=1
Indicate that automatic splitting and linking of words should split on hyphens in multiword expressions with spaces in them (splitting on hyphens is automatic if there are no spaces in the term).
|pagename=
Override the page name used to compute default values of various sorts. Useful when testing, for documentation pages, etc.

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.

Autosplitting

All templates using this module use an intelligent autosplitting algorithm to link portions of multipart and multiword expressions, as follows:

  • The module will automatically split and link distinct space-separated words, similarly to {{head}}; hence, tout le monde will be linked as [[tout]] [[le]] [[monde]].
  • It also splits on apostrophes in the middle of words and includes the apostrophe in the preceding portion. Hence, n’importe quoi will be linked as [[n']][[importe]] [[quoi]]. (An exception is made for three words, quelqu’un, c’est and aujourd’hui, which will not be split if they occur as part of larger expressions.)
  • In addition, parts of hyphenated compounds in single-word expressions will be linked individually, e.g. grand-chose will be linked as [[grand]]-[[chose]]. Hyphenated compound words will not be split if they occur in multiword expressions unless |splithyph=1 is specified, since the compound itself might be a valid word.

Suffix handling

If the term begins with a hyphen (-), it is assumed to be a suffix rather than a base form, and is categorized into Category:French suffixes and Category:French POS-forming suffixes rather than Category:French POSs (e.g. Category:French noun-forming suffixes rather than Category:French nouns).


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

-- 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

-- 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

				if not exists(pl) 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 exists(f) 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 exists(m) 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
		
		-- 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, "French adjectives with missing forms")
					return
				end
			end
		end
	end
}

return export