Module:fax-headword
Appearance
- This module lacks a documentation subpage. Please create it.
- Useful links: subpage list • links • transclusions • testcases • sandbox
----adaptation of [[Module:es-headoword]]
local export = {}
local pos_functions = {}
local u = mw.ustring.char
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local gsub = mw.ustring.gsub
local m_links = require("Module:links")
local com = require("Module:es-common") --using the Spanish module
local lang = require("Module:languages").getByCode("fax")
local langname = lang:getCanonicalName()
local PAGENAME = mw.title.getCurrentTitle().text
local V = com.V -- vowel regex class
local AV = com.AV -- accented vowel regex class
local C = com.C -- consonant regex class
local rsub = com.rsub
local suffix_categories = {
["adjectives"] = true,
["adverbs"] = true,
["nouns"] = true,
["verbs"] = true,
}
local prepositions = {
"a ", "de ", "da ", "du ", "do ", "dus ", "dos ", "das ", "en ", "in ", "no ", "nu ", "na ", "nos ", "nus ", "nas ", "pur ", "con ", "pa ","como ",
}
-- Add links around words. If multiword_only, do it only in multiword forms.
local function add_links(form, multiword_only)
if form == "" or form == " " then
return form
end
if not form:find("%[%[") then
if rfind(form, "[%s%p]") then --optimization to avoid loading [[Module:headword]] on single-word forms
local m_headword = require("Module:headword")
if m_headword.head_is_multiword(form) then
form = m_headword.add_multiword_links(form)
end
end
if not multiword_only and not form:find("%[%[") then
form = "[[" .. form .. "]]"
end
end
return form
end
local function track(page)
require("Module:debug").track("es-headword/" .. page)
return true
end
local function glossary_link(entry, text)
text = text or entry
return "[[Appendix:Glossary#" .. entry .. "|" .. text .. "]]"
end
local function check_all_missing(forms, plpos, tracking_categories)
for _, form in ipairs(forms) do
if type(form) == "table" then
form = form.term
end
if form then
local title = mw.title.new(form)
if title and not title.exists then
table.insert(tracking_categories, langname .. " " .. plpos .. " with red links in their headword lines")
end
end
end
end
-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
local tracking_categories = {}
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},
["json"] = {type = "boolean"},
["id"] = {},
}
local parargs = frame:getParent().args
if poscat == "nouns" and (not parargs[2] or parargs[2] == "") and parargs.pl2 then
track("noun-pl2-without-pl")
end
if pos_functions[poscat] then
for key, val in pairs(pos_functions[poscat].params) do
params[key] = val
end
end
local args = require("Module:parameters").process(parargs, params)
local data = {
lang = lang,
pos_category = poscat,
categories = {},
heads = args["head"],
genders = {},
inflections = {},
id = args["id"],
}
local lemma = m_links.remove_links(data.heads[1] or PAGENAME)
if lemma:find("^%-") then -- suffix
if poscat:find(" forms?$") then
data.pos_category = "suffix forms"
else
data.pos_category = "suffixes"
end
if suffix_categories[poscat] then
local singular_poscat = poscat:gsub("s$", "")
table.insert(data.categories, langname .. " " .. singular_poscat .. "-forming suffixes")
end
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data, tracking_categories, frame)
end
if args["json"] then
return require("Module:JSON").toJSON(data)
end
return require("Module:headword").full_headword(data)
.. require("Module:utilities").format_categories(tracking_categories, lang)
end
local function make_plural(form, special)
local retval = require("Module:romance utilities").handle_multiword(form, special, make_plural, prepositions)
if retval then
return retval
end
-- ends in vowel (there are many irregularities)
if rfind(form, "[áéíóúaeiou]$") then return {form .. "s"} end
-- ends in -al -> -ais (some nouns edning in -al have a plural with -aris, these have to be specified manually)
if rfind(form, "al$") then return {rsub(form, "al", "ais")} end
--ends in -Vn-> -Vns/-Vs
if rfind(form, "[áéíóú]n$") then return {{term=rsub(form, "n", "s"), l={"Lagarteiru", "Mañegu"}}, {term=rsub(form, "n", "ns"), l={"Valverdeñu"}}} end
-- ends in -ol -> -oris
if rfind(form, "ol$") then return {rsub(form, "ol", "oris")} end
-- ends in -itú -> -itudis
if rfind(form, "itú$") then return {rsub(form, "itú", "itudis")} end
-- ends in -il -> -ís
if rfind(form, "il$") then return {rsub(form, "il", "ís")} end
-- ends in -el -> -eris (most common, there are other orms)
if rfind(form, "el$") then return {rsub(form, "el", "eris")} end
-- ends in a vowel + z (rare)
if rfind(form, V .. "z$") then
return {rsub(form, "z$", "cis")}
end
local syllables = com.syllabify(form)
-- ends in s with more than 1 syllable, last syllable unstressed
if syllables[2] and rfind(form, "s$") and not rfind(syllables[#syllables], AV) then
return {form}
end
-- ends in an accented vowel + consonant
if rfind(form, AV .. C .. "$") then
return {rsub(form, "(.)(.)$", function(vowel, consonant)
return com.remove_accent[vowel] .. consonant .. "is"
end)}
end
-- ends in a vowel + certain consonants
if rfind(form, "[aeiou][lrnmdjs]$") then
-- two or more syllables: add stress mark to plural; e.g. joven -> jóvenes
if syllables[2] and rfind(form, "n$") then
syllables[#syllables - 1] = com.add_accent_to_syllable(syllables[#syllables - 1])
return {table.concat(syllables, "") .. "is"}
end
return {form .. "is"}
else
return {form .. "is"}
end
return nil
end
local function make_feminine(form, special)
local retval = require("Module:romance utilities").handle_multiword(form, special, make_feminine, prepositions)
if retval then
if #retval ~= 1 then
error("Internal error: Should have one return value for make_feminine: " .. table.concat(retval, ","))
end
return retval[1]
end
if form:find("ol$") then
local retval = form:gsub("ol$", "ora") -- discard second retval
return retval
end
if form:find("au$") then
local retval = form:gsub("au$", "á") -- discard second retval
return retval
end
if form:find("u$") then
local retval = form:gsub("u$", "a") -- discard second retval
return retval
end
return form
end
local function make_masculine(form, special)
local retval = require("Module:romance utilities").handle_multiword(form, special, make_masculine, prepositions)
if retval then
if #retval ~= 1 then
error("Internal error: Should have one return value for make_masculine: " .. table.concat(retval, ","))
end
return retval[1]
end
if form:find("ora$") then
local retval = form:gsub("ora$", "ol") -- discard second retval
return retval
end
if form:find("a$") then
local retval = form:gsub("a$", "u") -- discard second retval
return retval
end
if form:find("á$") then
local retval = form:gsub("á$", "au") -- discard second retval
return retval
end
return form
end
local function do_adjective(args, data, tracking_categories, is_superlative)
local feminines = {}
local plurals = {}
local masculine_plurals = {}
local feminine_plurals = {}
if args.sp and not require("Module:romance utilities").allowed_special_indicators[args.sp] then
local indicators = {}
for indic, _ in pairs(require("Module:romance utilities").allowed_special_indicators) do
table.insert(indicators, "'" .. indic .. "'")
end
table.sort(indicators)
error("Special inflection indicator beginning can only be " ..
mw.text.listToText(indicators) .. ": " .. args.sp)
end
local argsf = args.f or {}
local argspl = args.pl or {}
local argsmpl = args.mpl or {}
local argsfpl = args.fpl or {}
if args.inv then
-- invariable adjective
table.insert(data.inflections, {label = "invariable"})
table.insert(data.categories, langname .. " indeclinable adjectives")
if args.sp or #argsf > 0 or #argspl > 0 or #argsmpl > 0 or #argsfpl > 0 then
error("Can't specify inflections with an invariable adjective")
end
else
local lemma = m_links.remove_links(data.heads[1] or PAGENAME)
-- Gather feminines.
if #argsf == 0 then
argsf = {"+"}
end
for _, f in ipairs(argsf) do
if f == "+" then
-- Generate default feminine.
f = make_feminine(lemma, args.sp)
elseif f == "#" then
f = lemma
end
table.insert(feminines, f)
end
if #argspl > 0 and (#argsmpl > 0 or #argsfpl > 0) then
error("Can't specify both pl= and mpl=/fpl=")
end
if #feminines == 1 and feminines[1] == lemma then
-- Feminine like the masculine; just generate a plural
if #argspl == 0 then
argspl = {"+"}
end
elseif #argspl == 0 then
-- Distinct masculine and feminine plurals
if #argsmpl == 0 then
argsmpl = {"+"}
end
if #argsfpl == 0 then
argsfpl = {"+"}
end
end
for _, pl in ipairs(argspl) do
if pl == "+" then
-- Generate default plural.
local defpls = make_plural(lemma, args.sp)
if not defpls then
error("Unable to generate default plural of '" .. lemma .. "'")
end
for _, defpl in ipairs(defpls) do
table.insert(plurals, defpl)
end
elseif pl == "#" then
table.insert(plurals, lemma)
else
table.insert(plurals, pl)
end
end
for _, mpl in ipairs(argsmpl) do
if mpl == "+" then
-- Generate default masculine plural.
local defpls = make_plural(lemma, args.sp)
if not defpls then
error("Unable to generate default plural of '" .. lemma .. "'")
end
for _, defpl in ipairs(defpls) do
table.insert(masculine_plurals, defpl)
end
elseif mpl == "#" then
table.insert(masculine_plurals, lemma)
else
table.insert(masculine_plurals, mpl)
end
end
for _, fpl in ipairs(argsfpl) do
if fpl == "+" then
for _, f in ipairs(feminines) do
-- Generate default feminine plural.
local defpls = make_plural(f, args.sp)
if not defpls then
error("Unable to generate default plural of '" .. f .. "'")
end
for _, defpl in ipairs(defpls) do
table.insert(feminine_plurals, defpl)
end
end
elseif fpl == "#" then
table.insert(feminine_plurals, lemma)
else
table.insert(feminine_plurals, fpl)
end
end
if args.mapoc then
check_all_missing(args.mapoc, "adjectives", tracking_categories)
end
check_all_missing(feminines, "adjectives", tracking_categories)
check_all_missing(plurals, "adjectives", tracking_categories)
check_all_missing(masculine_plurals, "adjectives", tracking_categories)
check_all_missing(feminine_plurals, "adjectives", tracking_categories)
if args.mapoc and #args.mapoc > 0 then
args.mapoc.label = "masculine singular before a noun"
table.insert(data.inflections, args.mapoc)
end
-- Make sure there are feminines given and not same as lemma.
if #feminines > 0 and not (#feminines == 1 and feminines[1] == lemma) then
feminines.label = "feminine"
feminines.accel = {form = "f|s"}
table.insert(data.inflections, feminines)
end
if #plurals > 0 then
plurals.label = "plural"
plurals.accel = {form = "p"}
table.insert(data.inflections, plurals)
end
if #masculine_plurals > 0 then
masculine_plurals.label = "masculine plural"
masculine_plurals.accel = {form = "m|p"}
table.insert(data.inflections, masculine_plurals)
end
if #feminine_plurals > 0 then
feminine_plurals.label = "feminine plural"
feminine_plurals.accel = {form = "f|p"}
table.insert(data.inflections, feminine_plurals)
end
end
if args.comp and #args.comp > 0 then
check_all_missing(args.comp, "adjectives", tracking_categories)
args.comp.label = "comparative"
table.insert(data.inflections, args.comp)
end
if args.sup and #args.sup > 0 then
check_all_missing(args.sup, "adjectives", tracking_categories)
args.sup.label = "superlative"
table.insert(data.inflections, args.sup)
end
if args.irreg and is_superlative then
table.insert(data.categories, langname .. " irregular superlative adjectives")
end
end
pos_functions["adjectives"] = {
params = {
["inv"] = {type = "boolean"}, --invariable
["sp"] = {}, -- special indicator: "first", "first-last", etc.
["f"] = {list = true}, --feminine form(s)
["pl"] = {list = true}, --plural override(s)
["fpl"] = {list = true}, --feminine plural override(s)
["mpl"] = {list = true}, --masculine plural override(s)
["mapoc"] = {list = true}, --masculine apocopated (before a noun)
["comp"] = {list = true}, --comparative(s)
["sup"] = {list = true}, --superlative(s)
},
func = function(args, data, tracking_categories)
return do_adjective(args, data, tracking_categories, false)
end
}
pos_functions["comparative adjectives"] = {
params = {
["inv"] = {type = "boolean"}, --invariable
["sp"] = {}, -- special indicator: "first", "first-last", etc.
["f"] = {list = true}, --feminine form(s)
["pl"] = {list = true}, --plural override(s)
["fpl"] = {list = true}, --feminine plural override(s)
["mpl"] = {list = true}, --masculine plural override(s)
},
func = function(args, data, tracking_categories)
return do_adjective(args, data, tracking_categories, false)
end
}
pos_functions["superlative adjectives"] = {
params = {
["inv"] = {type = "boolean"}, --invariable
["sp"] = {}, -- special indicator: "first", "first-last", etc.
["f"] = {list = true}, --feminine form(s)
["pl"] = {list = true}, --plural override(s)
["fpl"] = {list = true}, --feminine plural override(s)
["mpl"] = {list = true}, --masculine plural override(s)
["irreg"] = {type = "boolean"},
},
func = function(args, data, tracking_categories)
return do_adjective(args, data, tracking_categories, true)
end
}
pos_functions["past participles"] = {
params = {
[1] = {}, --FIXME: ignore this until we've fixed the uses
["inv"] = {type = "boolean"}, --invariable
["sp"] = {}, -- special indicator: "first", "first-last", etc.
},
func = function(args, data, tracking_categories)
return do_adjective(args, data, tracking_categories, false)
end
}
pos_functions["adverbs"] = {
params = {
["sup"] = {list = true}, --superlative(s)
},
func = function(args, data, tracking_categories, frame)
if #args.sup > 0 then
check_all_missing(args.sup, "adverbs", tracking_categories)
args.sup.label = "superlative"
table.insert(data.inflections, args.sup)
end
end,
}
pos_functions["cardinal numbers"] = {
params = {
["f"] = {list = true}, --feminine(s)
["mapoc"] = {list = true}, --masculine apocopated form(s)
},
func = function(args, data, tracking_categories, frame)
data.pos_category = "numerals"
table.insert(data.categories, 1, langname .. " cardinal numbers")
if #args.f > 0 then
table.insert(data.genders, "m")
check_all_missing(args.f, "numerals", tracking_categories)
args.f.label = "feminine"
table.insert(data.inflections, args.f)
end
if #args.mapoc > 0 then
check_all_missing(args.mapoc, "numerals", tracking_categories)
args.mapoc.label = "masculine before a noun"
table.insert(data.inflections, args.mapoc)
end
end,
}
-- Display information for a noun's gender
-- This is separate so that it can also be used for proper nouns
function noun_gender(args, data)
local gender = args[1]
table.insert(data.genders, gender)
if #data.genders == 0 then
table.insert(data.genders, "?")
end
end
pos_functions["proper nouns"] = {
params = {
[1] = {},
},
func = function(args, data)
noun_gender(args, data)
end
}
-- Display additional inflection information for a noun
pos_functions["nouns"] = {
params = {
[1] = {required = true, default = "m"}, --gender
["g2"] = {}, --second gender
["e"] = {type = "boolean"}, --epicene
[2] = {list = "pl"}, --plural override(s)
["f"] = {list = true}, --feminine form(s)
["m"] = {list = true}, --masculine form(s)
["fpl"] = {list = true}, --feminine plural override(s)
["mpl"] = {list = true}, --masculine plural override(s)
["dim"] = {list = true}, --diminutive(s)
["aug"] = {list = true}, --diminutive(s)
["pej"] = {list = true}, --pejorative(s)
["qpl"] = {list = true, allow_holes = true},
},
func = function(args, data, tracking_categories)
local allowed_genders = {
["m"] = true,
["f"] = true,
["m-p"] = true,
["f-p"] = true,
["mf"] = true,
["mf-p"] = true,
["mfbysense"] = true,
["mfbysense-p"] = true,
}
local lemma = m_links.remove_links(
(#data.heads > 0 and data.heads[1]) or PAGENAME
)
if args[1] == "m-f" then
args[1] = "mf"
elseif args[1] == "mfp" or args[1] == "m-f-p" then
args[1] = "mf-p"
end
if not allowed_genders[args[1]] then error("Unrecognized gender: " .. args[1]) end
table.insert(data.genders, args[1])
if args.g2 then table.insert(data.genders, args.g2) end
if args["e"] then
table.insert(data.categories, langname .. " epicene nouns")
table.insert(data.inflections, {label = glossary_link("epicene")})
end
local plurals = {}
if args[1]:find("%-p$") then
table.insert(data.inflections, {label = glossary_link("plural only")})
if #args[2] > 0 then
error("Can't specify plurals of a plurale tantum noun")
end
else
-- Gather plurals, handling requests for default plurals
for i, pl in ipairs(args[2]) do
if pl == "+" then
local default_pls = make_plural(lemma)
for _, defp in ipairs(default_pls) do
table.insert(plurals, defp)
end
elseif pl == "#" then
table.insert(plurals, lemma)
elseif pl:find("^%+") then
pl = require("Module:romance utilities").get_special_indicator(pl)
local default_pls = make_plural(lemma, pl)
for _, defp in ipairs(default_pls) do
table.insert(plurals, defp)
end
else
table.insert(plurals, {term=pl, l=args.qpl[i] and {args.qpl[i]} or nil})
end
end
-- Check for special plural signals
local mode = nil
if #plurals > 0 and #plurals[1].term == 1 then
if plurals[1].term == "?" or plurals[1].term == "!" or plurals[1].term == "-" or plurals[1].term == "~" then
mode = plurals[1].term
table.remove(plurals, 1) -- Remove the mode parameter
else
error("Unexpected plural code")
end
end
if mode == "?" then
-- Plural is unknown
table.insert(data.categories, langname .. " nouns with unknown or uncertain plurals")
elseif mode == "!" then
-- Plural is not attested
table.insert(data.inflections, {label = "plural not attested"})
table.insert(data.categories, langname .. " nouns with unattested plurals")
return
elseif mode == "-" then
-- Uncountable noun; may occasionally have a plural
table.insert(data.categories, langname .. " uncountable nouns")
-- If plural forms were given explicitly, then show "usually"
if #plurals > 0 then
table.insert(data.inflections, {label = "usually " .. glossary_link("uncountable")})
table.insert(data.categories, langname .. " countable nouns")
else
table.insert(data.inflections, {label = glossary_link("uncountable")})
end
else
-- Countable or mixed countable/uncountable
if #plurals == 0 then
local pls = make_plural(lemma)
if pls then
for _, pl in ipairs(pls) do
table.insert(plurals, pl)
end
end
end
if mode == "~" then
-- Mixed countable/uncountable noun, always has a plural
table.insert(data.inflections, {label = glossary_link("countable") .. " and " .. glossary_link("uncountable")})
table.insert(data.categories, langname .. " uncountable nouns")
table.insert(data.categories, langname .. " countable nouns")
else
-- Countable nouns
table.insert(data.categories, langname .. " countable nouns")
end
end
end
-- Gather masculines/feminines. For each one, generate the corresponding plural(s).
local function handle_mf(mfs, inflect, default_plurals)
local retval = {}
for _, mf in ipairs(mfs) do
if mf == "1" then
track("noun-mf-1")
end
if mf == "1" or mf == "+" then
-- Generate default feminine.
mf = inflect(lemma)
elseif mf == "#" then
mf = lemma
end
local special = require("Module:romance utilities").get_special_indicator(mf)
if special then
mf = inflect(lemma, special)
end
table.insert(retval, mf)
local mfpls = make_plural(mf, special)
if mfpls then
for _, mfpl in ipairs(mfpls) do
-- Add an accelerator for each masculine/feminine plural whose lemma
-- is the corresponding singular, so that the accelerated entry
-- that is generated has a definition that looks like
-- # {{plural of|es|MFSING}}
table.insert(default_plurals, {term = mfpl, accel = {form = "p", lemma = mf}})
end
end
end
return retval
end
local feminine_plurals = {}
local feminines = handle_mf(args.f, make_feminine, feminine_plurals)
local masculine_plurals = {}
local masculines = handle_mf(args.m, make_masculine, masculine_plurals)
local function handle_mf_plural(mfpl, default_plurals, singulars)
local new_mfpls = {}
for i, mfpl in ipairs(mfpl) do
local accel
if #mfpl == #singulars then
-- If same number of overriding masculine/feminine plurals as singulars,
-- assume each plural goes with the corresponding singular
-- and use each corresponding singular as the lemma in the accelerator.
-- The generated entry will have # {{plural of|es|SINGULAR}} as the
-- definition.
accel = {form = "p", lemma = singulars[i]}
else
accel = nil
end
if mfpl == "+" then
for _, defpl in ipairs(default_plurals) do
-- defpl is already a table
table.insert(new_mfpls, defpl)
end
elseif mfpl == "#" then
table.insert(new_mfpls, {term = lemma, accel = accel})
elseif mfpl:find("^%+") then
mfpl = require("Module:romance utilities").get_special_indicator(mfpl)
for _, mf in ipairs(singulars) do
local default_mfpls = make_plural(mf, mfpl)
for _, defp in ipairs(default_mfpls) do
table.insert(new_mfpls, {term = defp, accel = accel})
end
end
else
table.insert(new_mfpls, {term = mfpl, accel = accel})
end
end
return new_mfpls
end
if #args.fpl > 0 then
-- Override any existing feminine plurals.
feminine_plurals = handle_mf_plural(args.fpl, feminine_plurals, feminines)
end
if #args.mpl > 0 then
-- Override any existing masculine plurals.
masculine_plurals = handle_mf_plural(args.mpl, masculine_plurals, masculines)
end
check_all_missing(plurals, "nouns", tracking_categories)
check_all_missing(feminines, "nouns", tracking_categories)
check_all_missing(feminine_plurals, "nouns", tracking_categories)
check_all_missing(masculines, "nouns", tracking_categories)
check_all_missing(masculine_plurals, "nouns", tracking_categories)
check_all_missing(args.dim, "nouns", tracking_categories)
check_all_missing(args.aug, "nouns", tracking_categories)
check_all_missing(args.pej, "nouns", tracking_categories)
local function redundant_plural(pl)
for _, p in ipairs(plurals) do
if p == pl then
return true
end
end
return false
end
for _, mpl in ipairs(masculine_plurals) do
if redundant_plural(mpl) then
track("noun-redundant-mpl")
end
end
for _, fpl in ipairs(feminine_plurals) do
if redundant_plural(fpl) then
track("noun-redundant-fpl")
end
end
if #plurals > 0 then
plurals.label = "plural"
plurals.accel = {form = "p"}
for _, pl in ipairs(plurals) do
if pl.l then
local dialects = {}
for _, l in ipairs(pl.l) do
table.insert(dialects, (l:gsub("Lagarteiru", "L"):gsub("Mañegu", "M"):gsub("Valverdeñu", "V"):gsub(",%s*", "|")))
end
plurals.accel.form = plurals.accel.form .. "|" .. table.concat(dialects)
end
end
table.insert(data.inflections, plurals)
end
if #feminines > 0 then
feminines.label = "feminine"
feminines.accel = {form = "f"}
table.insert(data.inflections, feminines)
end
if #feminine_plurals > 0 then
feminine_plurals.label = "feminine plural"
table.insert(data.inflections, feminine_plurals)
end
if #masculines > 0 then
masculines.label = "masculine"
table.insert(data.inflections, masculines)
end
if #masculine_plurals > 0 then
masculine_plurals.label = "masculine plural"
table.insert(data.inflections, masculine_plurals)
end
if #args.dim > 0 then
args.dim.label = glossary_link("diminutive")
table.insert(data.inflections, args.dim)
end
if #args.aug > 0 then
args.aug.label = glossary_link("augmentative")
table.insert(data.inflections, args.aug)
end
if #args.pej > 0 then
args.pej.label = glossary_link("pejorative")
table.insert(data.inflections, args.pej)
end
end
}
return export