local export = {}
local pos_functions = {}
local headword_utilities_module = "Module:headword utilities"
local inflection_utilities_module = "Module:inflection utilities"
local lang = require("Module:languages").getByCode("de")
local legal_gender = {
= true,
= true,
= true,
= true,
}
local gender_names = {
= "masculine",
= "feminine",
= "neuter",
}
local legal_verb_classes = {
= true,
= true,
= true,
= true,
= true,
= true,
= true,
}
local function ine(val)
if val == "" then return nil else return val end
end
local function glossary_link(entry, text)
text = text or entry
return "]"
end
local function track(page)
require("Module:debug").track("de-headword/" .. page)
return true
end
-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
local args = frame:getParent().args
PAGENAME = mw.title.getCurrentTitle().text
local poscat = frame.args or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
local class = frame.args; if class == "" then class = nil end
local data = {lang = lang, pos_category = poscat, categories = {}, heads = {}, genders = {}, inflections = {}}
if pos_functions then
pos_functions(class, args, data)
end
return
require("Module:headword").full_headword(data)
end
local function old_adjectives(class, args, data)
track("de-adj-old")
local params = {
= {list = "comp"},
= {list = "sup"},
= {list = true},
}
local args = require("Module:parameters").process(args, params)
data.heads = args
if args == "-" then
table.insert(data.inflections, {label = "not comparable"})
table.insert(data.categories, "German uncomparable adjectives")
return
end
if #args > 0 then
for i, form in ipairs(args) do
args = {term = (form == "er" and PAGENAME .. "er" or form),
accel = {form = "comparative"}}
end
else
args = {request = true}
track("de-adj lacking comparative")
end
args.label = glossary_link("comparative")
table.insert(data.inflections, args)
if #args > 0 then
for i, form in ipairs(args) do
args = {
term = "am ]",
accel = {form = "superlative"}}
end
else
args = {request = true}
track("de-adj lacking superlative")
end
args.label = glossary_link("superlative")
table.insert(data.inflections, args)
end
pos_functions.adjectives = function(class, args, data, proper)
-- Compatibility with old calling convention, either if old= is given or any arg no longer supported is given.
if ine(args.old) or ine(args) or ine(args.comp1) or ine(args.comp2) or ine(args.comp3) or
ine(args.sup1) or ine(args.sup2) or ine(args.sup3) or args == "-" then
return old_adjectives(class, args, data)
else
-- Remove this code once we convert to the new format.
track("de-adj-need-old")
end
local alternant_multiword_spec = require("Module:de-adjective").do_generate_forms(args, nil, "from headword")
data.heads = alternant_multiword_spec.args.head
data.id = alternant_multiword_spec.args.id
data.sort = alternant_multiword_spec.args.sort
local function do_adj_form(slot, label, should_be_present, accel_form)
local forms = alternant_multiword_spec.forms
local retval
if not forms then
if not should_be_present then
return
end
retval = {label = "no " .. label}
else
retval = {label = label, accel = accel_form and {form = accel_form} or nil}
local prev_footnotes
for _, form in ipairs(forms) do
local footnotes = form.footnotes
if footnotes and prev_footnotes and require("Module:table").deepEquals(footnotes, prev_footnotes) then
footnotes = nil
end
prev_footnotes = form.footnotes
local quals, refs = require(inflection_utilities_module).
convert_footnotes_to_qualifiers_and_references(footnotes)
local term = form.form
table.insert(retval, {term = term, q = quals, refs = refs, genders = genders})
end
end
table.insert(data.inflections, retval)
end
if alternant_multiword_spec.props.indecl then
table.insert(data.inflections, {label = glossary_link("indeclinable")})
if alternant_multiword_spec.props.predonly then
table.insert(data.inflections, {label = "predicative only"})
elseif alternant_multiword_spec.props.nopred then
table.insert(data.inflections, {label = "no predicative form"})
end
else
if alternant_multiword_spec.props.nopred then
table.insert(data.inflections, {label = "no predicative form"})
end
do_adj_form("str_nom_m", "strong nominative masculine singular", true)
local should_comp_sup =
alternant_multiword_spec.forms.comp_pred or alternant_multiword_spec.forms.sup_pred or
alternant_multiword_spec.forms.comp_str_nom_m or alternant_multiword_spec.forms.sup_str_nom_m
if not should_comp_sup then
table.insert(data.inflections, {label = "not comparable"})
else
-- If there is no predicative comparative, but there is an attributive comparative, include it;
-- otherwise, include the predicative comparative (if any). If there is no comparative but a superlative,
-- this will display "no comparative".
if not alternant_multiword_spec.forms.comp_pred and alternant_multiword_spec.forms.comp_str_nom_m then
do_adj_form("comp_str_nom_m", "strong comparative nominative masculine singular", true)
else
do_adj_form("comp_pred", glossary_link("comparative"), true, "comparative")
end
-- Same as above, for the superlative.
if not alternant_multiword_spec.forms.sup_pred and alternant_multiword_spec.forms.sup_str_nom_m then
do_adj_form("sup_str_nom_m", "strong superlative nominative masculine singular", true)
else
do_adj_form("sup_pred", glossary_link("superlative"), true, "superlative")
end
end
end
-- Add categories.
for _, cat in ipairs(alternant_multiword_spec.categories) do
table.insert(data.categories, cat)
end
-- Use the "linked" form of the lemma as the head if no head= explicitly given.
data.no_redundant_head_cat = true -- always set since we have a different lemma linking algorithm from ].
if #data.heads == 0 then
data.heads = {}
local lemmas = alternant_multiword_spec.forms.the_lemma or {}
for _, lemma_obj in ipairs(lemmas) do
local head = alternant_multiword_spec.args.nolinkhead and lemma_obj.form or
require(headword_utilities_module).add_links_to_multiword_term(lemma_obj.form,
{split_hyphen_when_space = alternant_multiword_spec.args.splithyph})
local quals, refs = require(inflection_utilities_module).
convert_footnotes_to_qualifiers_and_references(lemma_obj.footnotes)
table.insert(data.heads, {term = head, q = quals, refs = refs})
end
end
end
local function old_nouns(class, args, data)
track("de-noun-old")
local params = {
= {list = "g", default = "?"},
= {list = "gen"},
= {list = "pl"},
= {list = "dim"},
= {list = true},
= {list = true},
= {list = true},
= {type = "boolean"},
}
local args = require("Module:parameters").process(args, params)
data.heads = args
-- Gender
for _, g in ipairs(args) do
if legal_gender then
table.insert(data.genders, g)
if g == "p" then
table.insert(data.categories, "German pluralia tantum")
else
table.insert(data.categories, "German " .. gender_names .. " nouns")
end
else
if g == "m-s" or g == "f-s" or g == "n-s" or g == "m-p" or g == "f-p" or g == "n-p" then
require("Module:debug").track("de-headword/genders")
end
table.insert(data.genders, "?")
end
end
if args ~= "p" then
-- Genitive
if not args then
if args == "m" or args == "n" then
table.insert(args, PAGENAME .. "s")
else
table.insert(args, PAGENAME)
end
end
for i, form in ipairs(args) do
args = {term = form}
end
args.accel = {form = "gen|s"}
args.label = "genitive"
table.insert(data.inflections, args)
-- Plural
if not args and data.pos_category == "nouns" then
table.insert(args, PAGENAME .. "en")
end
if args == "-" then
table.insert(data.inflections, {label = "no plural"})
table.insert(data.categories, "German uncountable nouns")
elseif #args > 0 then
for i, form in ipairs(args) do
args = {term = form}
end
args.accel = {form = "p"}
args.label = "plural"
table.insert(data.inflections, args)
end
end
-- Diminutive
if #args > 0 then
for i, form in ipairs(args) do
args = {term = form, genders = {"n"}}
end
args.accel = {form = "diminutive", gender = "n"}
args.label = "diminutive"
table.insert(data.inflections, args)
end
-- Other gender
if #args.f > 0 then
args.f.label = "female"
if args.f == "in" then
args.f = PAGENAME .. "in"
end
if args.f == PAGENAME .. "in" then
args.f.accel = {form = "feminine", gender = "f"}
args.f.label = "feminine"
end
table.insert(data.inflections, args.f)
end
if #args.m > 0 then
args.m.label = "male"
table.insert(data.inflections, args.m)
end
end
pos_functions.nouns = function(class, args, data, proper)
-- Compatibility with old calling convention, either if old= is given or any arg no longer supported is given.
if ine(args.old) or ine(args) or ine(args) or ine(args) or ine(args.g1) or ine(args.g2) or ine(args.g3) or
ine(args.gen1) or ine(args.gen2) or ine(args.gen3) or ine(args.pl1) or ine(args.pl2) or ine(args.pl3) then
return old_nouns(class, args, data)
end
local m_de_noun = require("Module:de-noun")
local alternant_multiword_spec = m_de_noun.do_generate_forms(args, nil, "from headword", proper)
data.heads = alternant_multiword_spec.args.head
data.genders = alternant_multiword_spec.genders
data.id = alternant_multiword_spec.args.id
data.sort = alternant_multiword_spec.args.sort
if not proper then
data.pos_category = alternant_multiword_spec.pos
if alternant_multiword_spec.pos == "suffixes" then
table.insert(data.categories, "German noun-forming suffixes")
end
end
local function get_nom_articles(alternant_multiword_spec)
local articles = {}
local m_table = require("Module:table")
if alternant_multiword_spec.number == "pl" then
m_table.insertIfNot(articles, "]")
else
for _, gender in ipairs(alternant_multiword_spec.genders) do
if gender.spec == "m" then
m_table.insertIfNot(articles, "]")
elseif gender.spec == "f" then
m_table.insertIfNot(articles, "]")
elseif gender.spec == "n" then
m_table.insertIfNot(articles, "]")
else
error("Internal error: Unrecognized gender '" .. gender.spec .. "'")
end
end
end
return table.concat(articles, "/")
end
local function get_gen_s_articles(alternant_multiword_spec)
local articles = {}
local m_table = require("Module:table")
if alternant_multiword_spec.number == "pl" then
error("Internal error: Should not be called on plural-only nouns")
else
for _, gender in ipairs(alternant_multiword_spec.genders) do
if gender.spec == "m" or gender.spec == "n" then
m_table.insertIfNot(articles, "]")
elseif gender.spec == "f" then
m_table.insertIfNot(articles, "]")
else
error("Internal error: Unrecognized gender '" .. gender.spec .. "'")
end
end
end
return table.concat(articles, "/")
end
local function do_noun_form(slot, label, should_be_present, accel_form, genders, prefix)
local forms = alternant_multiword_spec.forms
local retval
if not forms then
if not should_be_present then
return
end
retval = {label = "no " .. label}
else
retval = {label = label, accel = accel_form and {form = accel_form} or nil}
local prev_footnotes
for _, form in ipairs(forms) do
local footnotes = form.footnotes
if footnotes and prev_footnotes and require("Module:table").deepEquals(footnotes, prev_footnotes) then
footnotes = nil
end
prev_footnotes = form.footnotes
local quals, refs = require(inflection_utilities_module).convert_footnotes_to_qualifiers_and_references(footnotes)
local term = form.form
if prefix then
if not term:find("]") then
term = "]"
end
term = prefix .. " " .. term
end
table.insert(retval, {term = term, q = quals, refs = refs, genders = genders})
end
end
table.insert(data.inflections, retval)
end
if proper then
table.insert(data.inflections, {label = glossary_link("proper noun")})
end
local decl_types = alternant_multiword_spec.decl_type
if decl_types and #decl_types > 0 then
local decl_descs = {}
for _, decl_type in ipairs(decl_types) do
table.insert(decl_descs, glossary_link(decl_type .. " declension", decl_type))
end
table.insert(data.inflections, {label = table.concat(decl_descs, " or ")})
end
local overall_adj = alternant_multiword_spec.props.overall_adj
local article = alternant_multiword_spec.props.article
local surname = alternant_multiword_spec.props.surname
local langname = alternant_multiword_spec.props.langname
local saw_f = false
local saw_mn = false
for _, gender in ipairs(alternant_multiword_spec.genders) do
if gender.spec == "f" then
saw_f = true
elseif gender.spec == "m" or gender.spec == "n" then
saw_mn = true
end
end
local fem_sg_only = not saw_mn and alternant_multiword_spec.number ~= "pl"
if not alternant_multiword_spec.first_noun and alternant_multiword_spec.first_adj then
table.insert(data.inflections, {label = "adjectival"})
end
if surname then
table.insert(data.inflections, {label = "surname"})
end
if langname then
table.insert(data.inflections, {label = "language name"})
end
if alternant_multiword_spec.number == "pl" then
table.insert(data.inflections, {label = glossary_link("plural only")})
end
if article then
table.insert(data.inflections, {label = "usually definite"})
end
if alternant_multiword_spec.number == "pl" then
if overall_adj then
do_noun_form("wk_nom_p", "definite plural", true, nil, nil, "]")
end
elseif surname then
do_noun_form("gen_m_s", "masculine genitive", true)
do_noun_form("gen_f_s", "feminine genitive", true)
do_noun_form("nom_p", "plural", true)
elseif langname then
do_noun_form("gen_s", "genitive", true)
do_noun_form("nom_s_alt", "alternative nominative (used with the definite article)", true)
do_noun_form("gen_s_alt", "alternative genitive", true)
-- There should be no plural; this will trigger the display of 'no plural'.
do_noun_form("nom_p", "plural", true)
elseif overall_adj then
if article then
if not fem_sg_only then
do_noun_form("wk_nom_s", "definite nominative", true, nil, nil, get_nom_articles(alternant_multiword_spec))
end
do_noun_form("wk_gen_s", "definite genitive", true, nil, nil, get_gen_s_articles(alternant_multiword_spec))
do_noun_form("wk_nom_p", "definite plural", not proper, nil, nil, "]")
else
do_noun_form("wk_nom_s", "definite nominative", true, nil, nil, get_nom_articles(alternant_multiword_spec))
do_noun_form("str_gen_s", "genitive", true, nil, nil, not saw_f and "(])" or nil)
if saw_f then
do_noun_form("wk_gen_s", "definite genitive", true, nil, nil, get_gen_s_articles(alternant_multiword_spec))
end
do_noun_form("str_nom_p", "plural", not proper)
do_noun_form("wk_nom_p", "definite plural", nil, nil, nil, "]")
end
else
if article then
do_noun_form("gen_s", "definite genitive", true, nil, nil, get_gen_s_articles(alternant_multiword_spec))
do_noun_form("nom_p", "definite plural", not proper, nil, nil, "]")
else
do_noun_form("gen_s", "genitive", true)
do_noun_form("nom_p", "plural", not proper)
end
end
-- FIXME: Should we include the article in the singular equivalent if .article is given? I have no examples to go by.
do_noun_form("sg", "singular")
do_noun_form("dim", "diminutive", nil, "diminutive", {"n"}, article and "]" or nil)
do_noun_form("m", "masculine", nil, nil, nil, article and "]" or nil)
do_noun_form("f", "feminine", nil, "feminine", nil, article and "]" or nil)
do_noun_form("n", "neuter", nil, "neuter", nil, article and "]" or nil)
-- Add categories.
for _, cat in ipairs(alternant_multiword_spec.categories) do
table.insert(data.categories, cat)
end
-- Use the "linked" form of the lemma as the head if no head= explicitly given.
data.no_redundant_head_cat = true -- always set since we have a different lemma linking algorithm from ].
if #data.heads == 0 then
data.heads = {}
local lemmas = m_de_noun.get_lemmas(alternant_multiword_spec, "linked variant")
for _, lemma_obj in ipairs(lemmas) do
local head = alternant_multiword_spec.args.nolinkhead and lemma_obj.form or
require(headword_utilities_module).add_links_to_multiword_term(lemma_obj.form,
{split_hyphen_when_space = alternant_multiword_spec.args.splithyph})
if article and (not overall_adj or fem_sg_only) then
head = get_nom_articles(alternant_multiword_spec) .. " " .. head
end
local quals, refs = require(inflection_utilities_module).
convert_footnotes_to_qualifiers_and_references(lemma_obj.footnotes)
table.insert(data.heads, {term = head, q = quals, refs = refs})
end
end
end
pos_functions = function(class, args, data)
return pos_functions.nouns(class, args, data, "proper noun")
end
pos_functions.verbs = function(class, args, data)
if args then -- old-style
local params = {
= {list = "pres", required = true},
= {list = "pres\1_qual", allow_holes = true},
= {list = "past", required = true},
= {list = "past\1_qual", allow_holes = true},
= {list = "pp", required = true},
= {list = "pp\1_qual", allow_holes = true},
= {list = "pastsubj"},
= {list = "pastsubj\1_qual", allow_holes = true},
= {list = true},
= {list = "aux\1_qual", allow_holes = true},
= {list = true},
= {list = true},
}
local args = require("Module:parameters").process(args, params)
data.heads = args
local function collect_forms(label, accel_form, forms, qualifiers)
if forms == "-" then
return {label = "no " .. label}
else
-- Disable this for now as deduplication between heardword and conjugation table doesn't work correctly.
-- local into_table = accel_form and {label = label, accel = {form = accel_form}} or {label = label}
local into_table = {label = label}
for i, form in ipairs(forms) do
table.insert(into_table, {term = form, q = qualifiers and {qualifiers} or nil})
end
return into_table
end
end
if #args.class > 0 then
local class_descs, cats = require("Module:de-verb").process_verb_classes(args.class)
for _, cats in ipairs(cats) do
table.insert(data.categories, cats)
end
table.insert(data.inflections, {label = require("Module:table").serialCommaJoin(class_descs, {conj = "or"})})
end
table.insert(data.inflections, collect_forms("third-person singular present", "3|s|pres", args, args.pres_qual))
table.insert(data.inflections, collect_forms("past tense", "1//3|s|pret", args, args.past_qual))
table.insert(data.inflections, collect_forms("past participle", "perf|part", args, args.pp_qual))
if #args > 0 then
table.insert(data.inflections, collect_forms("past subjunctive", "1//3|s|sub|II", args, args.pastsubj_qual))
end
if #args.aux > 0 then
table.insert(data.inflections, collect_forms("auxiliary", nil, args.aux, args.aux_qual))
end
return
end
local function get_headword_inflection(forms, label, accel_form)
if forms then
-- Disable this for now as deduplication between heardword and conjugation table doesn't work correctly.
-- local inflection = accel_form and {label = label, accel = {form = accel_form}} or {label = label}
local inflection = {label = label}
for _, form in ipairs(forms) do
local qualifiers
if form.footnotes then
qualifiers = {}
for _, footnote in ipairs(form.footnotes) do
footnote = footnote:gsub("^%$", "%1")
table.insert(qualifiers, footnote)
end
end
table.insert(inflection, {term = form.form, q = qualifiers})
end
return inflection
elseif label then
return {label = "no " .. label}
else
return {}
end
end
local alternant_multiword_spec = require("Module:de-verb").do_generate_forms(args, "from headword")
for _, cat in ipairs(alternant_multiword_spec.categories) do
table.insert(data.categories, cat)
end
table.insert(data.inflections, {label = table.concat(alternant_multiword_spec.verb_types, " or ")})
if #data.heads == 0 then
data.no_redundant_head_cat = true
for _, head in ipairs(alternant_multiword_spec.forms.infinitive_linked) do
table.insert(data.heads, head.form)
end
end
table.insert(data.inflections, get_headword_inflection(alternant_multiword_spec.forms.pres_3s,
"third-person singular present", "3|s|pres"))
local pret_3s = alternant_multiword_spec.forms.pret_3s
table.insert(data.inflections, get_headword_inflection(pret_3s, "past tense", "1//3|s|pret"))
table.insert(data.inflections, get_headword_inflection(alternant_multiword_spec.forms.perf_part,
"past participle", "perf|part"))
-- See if we need the past subjunctive, i.e. there exist past subjunctive forms whose stem is not the
-- same as some past tense form. To facilitate comparison, we truncate final -e in both preterite 3s
-- and past subjunctive 3s, to handle cases like subjunctive 'ginge aus' vs. preterite 'ging aus'.
-- We need to compare 3s forms (and not e.g. 3p forms, where the issue with truncating -e doesn't
-- occur) so we work correctly with impersonal verbs.
local need_past_subj
local truncated_pret_3s_forms = {}
if pret_3s then
for _, form in ipairs(pret_3s) do
local truncated_form = form.form:gsub("e$", ""):gsub("e ", " ") -- discard 2nd retval
table.insert(truncated_pret_3s_forms, truncated_form)
end
end
local subii_3s = alternant_multiword_spec.forms.subii_3s
local truncated_subii_3s_forms = {}
if subii_3s then
for _, form in ipairs(subii_3s) do
local truncated_form = form.form:gsub("e$", ""):gsub("e ", " ") -- discard 2nd retval
table.insert(truncated_subii_3s_forms, truncated_form)
end
end
for _, past_subj_form in ipairs(truncated_subii_3s_forms) do
local saw_same = false
for _, pret_3s_form in ipairs(truncated_pret_3s_forms) do
if past_subj_form == pret_3s_form then
saw_same = true
break
end
end
if not saw_same then
need_past_subj = true
break
end
end
if need_past_subj then
table.insert(data.inflections, get_headword_inflection(subii_3s, "past subjunctive", "1//3|s|sub|II"))
end
local auxes = alternant_multiword_spec.forms.aux
table.insert(data.inflections, get_headword_inflection(auxes, "auxiliary"))
end
return export