muca and Module:etymology/templates: Difference between pages
(Difference between pages)
Content deleted Content added
+cat |
new {{desc}}/{{desctree}} implementation supporting multiple terms, misc cleanups Tag: Reverted |
||
Line 1: | Line 1: | ||
local export = {} |
|||
==Romani== |
|||
===Noun=== |
|||
{{rom-noun|muc|f|a|i}} |
|||
local m_languages = require("Module:languages") |
|||
# [[cat]] |
|||
local m_etymology = require("Module:etymology") |
|||
local rsplit = mw.text.split |
|||
[[Category:rom:Cats]] |
|||
local rsubn = mw.ustring.gsub |
|||
[[Category:rom:Mammals]] |
|||
-- version of rsubn() that discards all but the first return value |
|||
[[io:muca]] |
|||
local function rsub(term, foo, bar) |
|||
[[scn:muca]] |
|||
local retval = rsubn(term, foo, bar) |
|||
return retval |
|||
end |
|||
local function track(page) |
|||
return require("Module:debug").track(page) |
|||
end |
|||
local function fetch_script(sc) |
|||
if sc then |
|||
return require("Module:scripts").getByCode(sc, true) |
|||
else |
|||
return nil |
|||
end |
|||
end |
|||
function export.etyl(frame) |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
[2] = {}, |
|||
["sort"] = {}, |
|||
} |
|||
local args = require("Module:parameters").process(frame:getParent().args, params) |
|||
local source = m_languages.getByCode(args[1], 1, "allow etym", "allow family") |
|||
local lang = args[2] |
|||
local sort_key = args["sort"] |
|||
-- Empty language means English, but "-" means no language. Yes, confusing... |
|||
if not lang then |
|||
lang = "en" |
|||
elseif lang == "-" then |
|||
lang = nil |
|||
end |
|||
if lang then |
|||
lang = m_languages.getByCode(lang, 2) |
|||
end |
|||
if lang and (lang:getCode() == "la" or lang:getCode() == "nl") then |
|||
track("etyl/" .. lang:getCode()) |
|||
track("etyl/" .. lang:getCode() .. "/" .. source:getCode()) |
|||
end |
|||
return m_etymology.format_etyl(lang, source, sort_key) |
|||
end |
|||
function export.cognate(frame) |
|||
local args = frame:getParent().args |
|||
if args.gloss then |
|||
track("cognate/gloss param") |
|||
end |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
[2] = {}, |
|||
[3] = {alias_of = "alt"}, |
|||
[4] = {alias_of = "t"}, |
|||
["alt"] = {}, |
|||
["g"] = {list = true}, |
|||
["id"] = {}, |
|||
["lit"] = {}, |
|||
["pos"] = {}, |
|||
["t"] = {}, |
|||
["gloss"] = {alias_of = "t"}, |
|||
["tr"] = {}, |
|||
["ts"] = {}, |
|||
["sc"] = {}, |
|||
["sort"] = {}, |
|||
} |
|||
args = require("Module:parameters").process(args, params) |
|||
local source = m_languages.getByCode(args[1], 1, "allow etym", "allow family") |
|||
local sc = fetch_script(args["sc"]) |
|||
return m_etymology.format_cognate( |
|||
{ |
|||
lang = source, |
|||
sc = sc, |
|||
term = args[2], |
|||
alt = args["alt"], |
|||
id = args["id"], |
|||
genders = args["g"], |
|||
tr = args["tr"], |
|||
ts = args["ts"], |
|||
gloss = args["t"], |
|||
pos = args["pos"], |
|||
lit = args["lit"] |
|||
}, |
|||
args["sort"]) |
|||
end |
|||
function export.noncognate(frame) |
|||
return export.cognate(frame) |
|||
end |
|||
local function parse_2_lang_args(frame, has_text, no_family) |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
[2] = {required = true, default = "und"}, |
|||
[3] = {}, |
|||
[4] = {alias_of = "alt"}, |
|||
[5] = {alias_of = "t"}, |
|||
["alt"] = {}, |
|||
["g"] = {list = true}, |
|||
["gloss"] = {alias_of = "t"}, |
|||
["id"] = {}, |
|||
["lit"] = {}, |
|||
["pos"] = {}, |
|||
["t"] = {}, |
|||
["tr"] = {}, |
|||
["ts"] = {}, |
|||
["sc"] = {}, |
|||
["nocat"] = {type = "boolean"}, |
|||
["sort"] = {}, |
|||
} |
|||
if has_text then |
|||
params["notext"] = {type = "boolean"} |
|||
params["nocap"] = {type = "boolean"} |
|||
end |
|||
local args = require("Module:parameters").process(frame:getParent().args, params) |
|||
local lang = m_languages.getByCode(args[1], 1) |
|||
local source = m_languages.getByCode(args[2], 2, "allow etym", not no_family and "allow family") |
|||
local sc = fetch_script(args["sc"]) |
|||
return args, lang, { |
|||
lang = source, |
|||
sc = sc, |
|||
term = args[3], |
|||
alt = args["alt"], |
|||
id = args["id"], |
|||
genders = args["g"], |
|||
tr = args["tr"], |
|||
ts = args["ts"], |
|||
gloss = args["t"], |
|||
pos = args["pos"], |
|||
lit = args["lit"] |
|||
} |
|||
end |
|||
function export.derived(frame) |
|||
local args, lang, term = parse_2_lang_args(frame) |
|||
return m_etymology.format_derived(lang, term, args["sort"], args["nocat"], "derived") |
|||
end |
|||
function export.inherited(frame) |
|||
local args, lang, term = parse_2_lang_args(frame, nil, "no family") |
|||
return m_etymology.format_inherited(lang, term, args["sort"], args["nocat"]) |
|||
end |
|||
function export.borrowed(frame) |
|||
local args, lang, term = parse_2_lang_args(frame) |
|||
return m_etymology.format_borrowed(lang, term, args["sort"], |
|||
false, true, args["nocat"], "plain") |
|||
end |
|||
function export.learned_borrowing(frame) |
|||
if frame:getParent().args.gloss then |
|||
track("learned_borrowing/gloss param") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.format_borrowed(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"], "learned") |
|||
end |
|||
function export.semi_learned_borrowing(frame) |
|||
if frame:getParent().args.gloss then |
|||
track("semi_learned_borrowing/gloss param") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.format_borrowed(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"], "semi-learned") |
|||
end |
|||
function export.orthographic_borrowing(frame) |
|||
if frame:getParent().args.gloss then |
|||
track("orthographic_borrowing/gloss param") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.format_borrowed(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"], "orthographic") |
|||
end |
|||
function export.unadapted_borrowing(frame) |
|||
if frame:getParent().args.gloss then |
|||
track("unadapted_borrowing/gloss param") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.format_borrowed(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"], "unadapted") |
|||
end |
|||
function export.calque(frame) |
|||
local args = frame:getParent().args |
|||
-- More informative error message. |
|||
if args["etyl lang"] or args["etyl term"] or args["etyl t"] or args["etyl tr"] then |
|||
error("{{[[Template:calque|calque]]}} no longer supports parameters beginning with etyl. " .. |
|||
"The parameters supported are similar to those used by " .. |
|||
"{{[[Template:der|der]]}}, {{[[Template:inh|inh]]}}, " .. |
|||
"{{[[Template:bor|bor]]}}. See [[Template:calque/documentation]] for more.") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.calque(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"]) |
|||
end |
|||
function export.partial_calque(frame) |
|||
if frame:getParent().args.gloss then |
|||
track("partial_calque/gloss param") |
|||
end |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.partial_calque(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"]) |
|||
end |
|||
function export.semantic_loan(frame) |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.semantic_loan(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"]) |
|||
end |
|||
function export.psm(frame) |
|||
local args, lang, term = parse_2_lang_args(frame, "has text") |
|||
return m_etymology.phono_semantic_matching(lang, term, args["sort"], |
|||
args["nocap"], args["notext"], args["nocat"]) |
|||
end |
|||
local function qualifier(content) |
|||
if content then |
|||
return table.concat{ |
|||
'<span class="ib-brac qualifier-brac">(</span>', |
|||
'<span class="ib-content qualifier-content">', |
|||
content, |
|||
'</span>', |
|||
'<span class="ib-brac qualifier-brac">)</span>' |
|||
} |
|||
end |
|||
end |
|||
local function add_tooltip(text, tooltip) |
|||
return '<span class="desc-arr" title="' .. tooltip .. '">' .. text .. '</span>' |
|||
end |
|||
local function desc_or_desc_tree(frame, desc_tree) |
|||
local params |
|||
if desc_tree then |
|||
params = { |
|||
[1] = {required = true, default = "gem-pro"}, |
|||
[2] = {required = true, list = "term", allow_holes = true, default = "*fuhsaz"}, |
|||
["notext"] = { type = "boolean" }, |
|||
["noalts"] = { type = "boolean" }, |
|||
["noparent"] = { type = "boolean" }, |
|||
} |
|||
else |
|||
params = { |
|||
[1] = { required = true, default = "en" }, |
|||
[2] = { list = "term", allow_holes = true, default = "word" }, |
|||
["alts"] = { type = "boolean" } |
|||
} |
|||
end |
|||
for k, v in pairs({ |
|||
[3] = { alias_of = "alt" }, |
|||
["alt"] = { list = true, allow_holes = true }, |
|||
[4] = { alias_of = "t" }, |
|||
-- FIXME, currently all genders refer to first term, for historical reasons |
|||
["g"] = { list = true, allow_holes = true }, |
|||
["gloss"] = { alias_of = "t", list = true, allow_holes = true }, |
|||
["id"] = { list = true, allow_holes = true }, |
|||
["lit"] = { list = true, allow_holes = true }, |
|||
["pos"] = { list = true, allow_holes = true }, |
|||
["t"] = { list = true, allow_holes = true }, |
|||
["tr"] = { list = true, allow_holes = true }, |
|||
["ts"] = { list = true, allow_holes = true }, |
|||
["sc"] = { list = true, allow_holes = true }, |
|||
["inh"] = { type = "boolean" }, |
|||
["partinh"] = { type = "boolean", list = "inh", allow_holes = true, require_index = true }, |
|||
["bor"] = { type = "boolean" }, |
|||
["partbor"] = { type = "boolean", list = "bor", allow_holes = true, require_index = true }, |
|||
["lbor"] = { type = "boolean" }, |
|||
["partlbor"] = { type = "boolean", list = "lbor", allow_holes = true, require_index = true }, |
|||
["slb"] = { type = "boolean" }, |
|||
["partslb"] = { type = "boolean", list = "slb", allow_holes = true, require_index = true }, |
|||
["der"] = { type = "boolean" }, |
|||
["partder"] = { type = "boolean", list = "der", allow_holes = true, require_index = true }, |
|||
["clq"] = { type = "boolean" }, |
|||
["partclq"] = { type = "boolean", list = "clq", allow_holes = true, require_index = true }, |
|||
["cal"] = { alias_of = "clq", type = "boolean" }, |
|||
["partcal"] = { alias_of = "partclq", type = "boolean", list = "cal", allow_holes = true, require_index = true }, |
|||
["calq"] = { alias_of = "clq", type = "boolean" }, |
|||
["partcalq"] = { alias_of = "partclq", type = "boolean", list = "calq", allow_holes = true, require_index = true }, |
|||
["calque"] = { alias_of = "clq", type = "boolean" }, |
|||
["partcalque"] = { alias_of = "partclq", type = "boolean", list = "calque", allow_holes = true, require_index = true }, |
|||
["pclq"] = { type = "boolean" }, |
|||
["partpclq"] = { type = "boolean", list = "pclq", allow_holes = true, require_index = true }, |
|||
["sml"] = { type = "boolean" }, |
|||
["partsml"] = { type = "boolean", list = "sml", allow_holes = true, require_index = true }, |
|||
["unc"] = { type = "boolean" }, |
|||
["partunc"] = { type = "boolean", list = "unc", allow_holes = true, require_index = true }, |
|||
["sclb"] = { type = "boolean" }, |
|||
["nolb"] = { type = "boolean" }, |
|||
["q"] = {}, |
|||
["partq"] = { list = "q", allow_holes = true, require_index = true }, |
|||
["sandbox"] = { type = "boolean" }, |
|||
}) do |
|||
params[k] = v |
|||
end |
|||
local namespace = mw.title.getCurrentTitle().nsText |
|||
local parent_args |
|||
if frame.args[1] then |
|||
parent_args = frame.args |
|||
else |
|||
parent_args = frame:getParent().args |
|||
end |
|||
if parent_args[3] then |
|||
track("descendants/arg3") |
|||
end |
|||
if parent_args[4] then |
|||
track("descendants/arg4") |
|||
end |
|||
local args = require("Module:parameters").process(parent_args, params) |
|||
if args.sandbox then |
|||
if namespace == "" or namespace == "Reconstruction" then |
|||
error("The sandbox module, Module:descendants tree/sandbox, should not be used in entries.") |
|||
end |
|||
end |
|||
local m_desctree |
|||
if desc_tree or args["alts"] then |
|||
if args.sandbox or require("Module:yesno")(frame.args.sandbox, false) then |
|||
m_desctree = require("Module:descendants tree/sandbox") |
|||
else |
|||
m_desctree = require("Module:descendants tree") |
|||
end |
|||
end |
|||
-- FIXME! Remove this after converting existing instances of multiple genders to a single gender param, comma-separated. |
|||
if args["g"].maxindex > 0 then |
|||
local genders = {} |
|||
for i = 1, args["g"].maxindex do |
|||
if args["g"][i] then |
|||
table.insert(genders, args["g"][i]) |
|||
end |
|||
end |
|||
args["g"] = {table.concat(genders, ",")} |
|||
args["g"].maxindex = 1 |
|||
end |
|||
-- Check for any remaining places where g2= might be used for the first term's second gender. |
|||
-- (Applies after the FIXME code just above is removed.) |
|||
if args["g"].maxindex > args[2].maxindex then |
|||
track("descendant/gender-no-term") |
|||
end |
|||
local lang = args[1] |
|||
lang = m_languages.getByCode(lang, 1, "allow etym") |
|||
local entryLang = m_languages.getNonEtymological(lang) |
|||
if not desc_tree and entryLang:getType() == "family" then |
|||
error("Cannot use language family code in [[Template:desc]].") |
|||
end |
|||
if lang:getCode() ~= entryLang:getCode() then |
|||
-- [[Special:WhatLinksHere/Template:tracking/descendant/etymological]] |
|||
track("descendant/etymological") |
|||
track("descendant/etymological/" .. lang:getCode()) |
|||
end |
|||
local languageName = lang:getCanonicalName() |
|||
languageName = mw.ustring.gsub(languageName, "^Proto%-", "") |
|||
local label |
|||
-- Find the maximum index among any of the list parameters. |
|||
local maxmaxindex = 0 |
|||
for k, v in pairs(args) do |
|||
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then |
|||
maxmaxindex = v.maxindex |
|||
end |
|||
end |
|||
local function get_arrow(index) |
|||
local function val(arg) |
|||
if index == 0 then |
|||
return args[arg] |
|||
else |
|||
return args["part" .. arg][index] |
|||
end |
|||
end |
|||
local arrow |
|||
if val("bor") then |
|||
arrow = add_tooltip("→", "borrowed") |
|||
elseif val("lbor") then |
|||
arrow = add_tooltip("→", "learned borrowing") |
|||
elseif val("slb") then |
|||
arrow = add_tooltip("→", "semi-learned borrowing") |
|||
elseif val("clq") then |
|||
arrow = add_tooltip("→", "calque") |
|||
elseif val("pclq") then |
|||
arrow = add_tooltip("→", "partial calque") |
|||
elseif val("sml") then |
|||
arrow = add_tooltip("→", "semantic loan") |
|||
elseif val("unc") and not val("der") then |
|||
arrow = add_tooltip(">", "inherited") |
|||
else |
|||
arrow = "" |
|||
end |
|||
-- allow der=1 in conjunction with bor=1 to indicate e.g. English "pars recta" |
|||
-- derived and borrowed from Latin "pars". |
|||
if val("der") then |
|||
arrow = arrow .. add_tooltip("⇒", "reshaped by analogy or addition of morphemes") |
|||
end |
|||
if val("unc")then |
|||
arrow = arrow .. add_tooltip("?", "uncertain") |
|||
end |
|||
if arrow ~= "" then |
|||
arrow = arrow .. " " |
|||
end |
|||
return arrow |
|||
end |
|||
local function get_post_qualifiers(index) |
|||
local function val(arg) |
|||
if index == 0 then |
|||
return args[arg] |
|||
else |
|||
return args["part" .. arg][index] |
|||
end |
|||
end |
|||
local postqs = {} |
|||
if val("inh") then |
|||
table.insert(postqs, qualifier("inherited")) |
|||
end |
|||
if val("lbor") then |
|||
table.insert(postqs, qualifier("learned")) |
|||
end |
|||
if val("slb") then |
|||
table.insert(postqs, qualifier("semi-learned")) |
|||
end |
|||
if val("clq") then |
|||
table.insert(postqs, qualifier("calque")) |
|||
end |
|||
if val("pclq") then |
|||
table.insert(postqs, qualifier("partial calque")) |
|||
end |
|||
if val("sml") then |
|||
table.insert(postqs, qualifier("semantic loan")) |
|||
end |
|||
-- FIXME, should we use the qualifier support in full_link() (in which case the qualifier precedes the term)? |
|||
if val("q") then |
|||
table.insert(postqs, require("Module:qualifier").format_qualifier(val("q"))) |
|||
end |
|||
if #postqs > 0 then |
|||
return " " .. table.concat(postqs, " ") |
|||
else |
|||
return "" |
|||
end |
|||
end |
|||
local parts = {} |
|||
local descendants = {} |
|||
local saw_descendants = false |
|||
local terms = {} |
|||
for i = 1, maxmaxindex do |
|||
local term = args[2][i] |
|||
local alt = args["alt"][i] |
|||
local id = args["id"][i] |
|||
local sc = args["sc"][i] and require("Module:scripts").getByCode(args["sc"][i], "sc" .. (i == 1 and "" or i)) |
|||
local tr = args["tr"][i] |
|||
local ts = args["ts"][i] |
|||
local gloss = args["t"][i] |
|||
local pos = args["pos"][i] |
|||
local lit = args["lit"][i] |
|||
local g = args["g"][i] and rsplit(args["g"][i], "%s*,%s*") or {} |
|||
if i == 1 then |
|||
if args["sclb"] then |
|||
if sc then |
|||
label = sc:getCanonicalName() |
|||
elseif not term then |
|||
error("When sclb=1, must specify sc= or 2=") |
|||
else |
|||
label = require("Module:scripts").findBestScript(term, lang):getCanonicalName() |
|||
end |
|||
else |
|||
label = languageName |
|||
end |
|||
end |
|||
local link = "" |
|||
if term ~= "-" then |
|||
link = require("Module:links").full_link( |
|||
{ |
|||
lang = entryLang, |
|||
sc = sc, |
|||
term = term, |
|||
alt = alt, |
|||
id = id, |
|||
tr = tr, |
|||
ts = ts, |
|||
genders = g, |
|||
gloss = gloss, |
|||
pos = pos, |
|||
lit = lit, |
|||
}, |
|||
nil, |
|||
true) |
|||
elseif ts or gloss or #g > 0 then |
|||
-- [[Special:WhatLinksHere/Template:tracking/descendant/no term]] |
|||
track("descendant/no term") |
|||
link = require("Module:links").full_link( |
|||
{ |
|||
lang = entryLang, |
|||
sc = sc, |
|||
ts = ts, |
|||
gloss = gloss, |
|||
genders = g, |
|||
}, |
|||
nil, |
|||
true) |
|||
link = link |
|||
:gsub("<small>%[Term%?%]</small> ", "") |
|||
:gsub("<small>%[Term%?%]</small> ", "") |
|||
:gsub("%[%[Category:[^%[%]]+ term requests%]%]", "") |
|||
else -- display no link at all |
|||
-- [[Special:WhatLinksHere/Template:tracking/descendant/no term or annotations]] |
|||
track("descendant/no term or annotations") |
|||
end |
|||
local arrow = get_arrow(i) |
|||
local postqs = get_post_qualifiers(i) |
|||
local alts |
|||
if desc_tree and term and term ~= "-" then |
|||
table.insert(terms, term) |
|||
descendants[i] = m_desctree.getDescendants(entryLang, term, id, maxmaxindex > 1) |
|||
if descendants[i] then |
|||
saw_descendants = true |
|||
end |
|||
end |
|||
descendants[i] = descendants[i] or "" |
|||
if desc_tree and not args["noalts"] or not desc_tree and args["alts"] then |
|||
-- [[Special:WhatLinksHere/Template:tracking/desc/alts]] |
|||
track("desc/alts") |
|||
alts = m_desctree.getAlternativeForms(entryLang, term) |
|||
else |
|||
alts = "" |
|||
end |
|||
local linktext = table.concat{link, alts, postqs} |
|||
if not args["notext"] then |
|||
linktext = arrow .. linktext |
|||
end |
|||
if linktext ~= "" then |
|||
table.insert(parts, linktext) |
|||
end |
|||
end |
|||
if desc_tree and not saw_descendants then |
|||
if #terms == 0 then |
|||
error("{{desctree}} invoked but no terms to retrieve descendants from") |
|||
elseif #terms == 1 then |
|||
error("No Descendants section was found in the entry [[" .. terms[1] .. |
|||
"]] under the header for " .. entryLang:getCanonicalName() .. ".") |
|||
else |
|||
for i, term in ipairs(terms) do |
|||
terms[i] = "[[" .. term .. "]]" |
|||
end |
|||
error("No Descendants section was found in any of the entries " .. |
|||
table.concat(terms, ", ") .. " under the header for " .. entryLang:getCanonicalName() .. ".") |
|||
end |
|||
end |
|||
descendants = table.concat(descendants) |
|||
if args["noparent"] then |
|||
return descendants |
|||
end |
|||
local initial_arrow = get_arrow(0) |
|||
local final_postqs = get_post_qualifiers(0) |
|||
local all_linktext = table.concat(parts, ", ") .. final_postqs .. descendants |
|||
if args["notext"] then |
|||
return all_linktext |
|||
elseif args["nolb"] then |
|||
return initial_arrow .. all_linktext |
|||
else |
|||
return table.concat{initial_arrow, label, ":", linktext ~= "" and " " or "", all_linktext} |
|||
end |
|||
end |
|||
function export.descendant(frame) |
|||
return desc_or_desc_tree(frame, false) .. require("Module:TemplateStyles")("Module:etymology/style.css") |
|||
end |
|||
function export.descendants_tree(frame) |
|||
return desc_or_desc_tree(frame, true) |
|||
end |
|||
-- Implementation of miscellaneous templates such as {{back-formation}}, {{clipping}}, |
|||
-- {{ellipsis}}, {{rebracketing}}, and {{reduplication}} that have a single |
|||
-- associated term. |
|||
function export.misc_variant(frame) |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
[2] = {}, |
|||
[3] = {alias_of = "alt"}, |
|||
[4] = {alias_of = "t"}, |
|||
["alt"] = {}, |
|||
["gloss"] = {alias_of = "t"}, |
|||
["g"] = {list = true}, |
|||
["id"] = {}, |
|||
["lit"] = {}, |
|||
["pos"] = {}, |
|||
["t"] = {}, |
|||
["tr"] = {}, |
|||
["ts"] = {}, |
|||
["sc"] = {}, |
|||
["nocap"] = {type = "boolean"}, -- should be processed in the template itself |
|||
["notext"] = {type = "boolean"}, |
|||
["nocat"] = {type = "boolean"}, |
|||
["sort"] = {}, |
|||
} |
|||
-- |ignore-params= parameter to module invocation specifies |
|||
-- additional parameter names to allow in template invocation, separated by |
|||
-- commas. They must consist of ASCII letters or numbers or hyphens. |
|||
local ignore_params = frame.args["ignore-params"] |
|||
if ignore_params then |
|||
ignore_params = mw.text.trim(ignore_params) |
|||
if not ignore_params:match "^[%w%-,]+$" then |
|||
error("Invalid characters in |ignore-params=: " .. ignore_params:gsub("[%w%-,]+", "")) |
|||
end |
|||
for param in ignore_params:gmatch "[%w%-]+" do |
|||
if params[param] then |
|||
error("Duplicate param |" .. param |
|||
.. " in |ignore-params=: already specified in params") |
|||
end |
|||
params[param] = {} |
|||
end |
|||
end |
|||
local args = require("Module:parameters").process(frame:getParent().args, params) |
|||
local lang = m_languages.getByCode(args[1], 1) |
|||
local sc = fetch_script(args["sc"]) |
|||
local parts = {} |
|||
if not args["notext"] then |
|||
table.insert(parts, frame.args["text"]) |
|||
end |
|||
if args[2] or args["alt"] then |
|||
if not args["notext"] then |
|||
table.insert(parts, " ") |
|||
table.insert(parts, frame.args["oftext"] or "of") |
|||
table.insert(parts, " ") |
|||
end |
|||
table.insert(parts, require("Module:links").full_link( |
|||
{ |
|||
lang = lang, |
|||
sc = sc, |
|||
term = args[2], |
|||
alt = args["alt"], |
|||
id = args["id"], |
|||
tr = args["tr"], |
|||
ts = args["ts"], |
|||
genders = args["g"], |
|||
gloss = args["t"], |
|||
pos = args["pos"], |
|||
lit = args["lit"], |
|||
}, |
|||
"term", |
|||
true)) |
|||
end |
|||
-- Allow |cat=, |cat2=, |cat3=, etc. They must be sequential. If |cat= |
|||
-- is not defined, |cat2= will not be checked. Empty categories are ignored. |
|||
local categories = {} |
|||
if not args["nocat"] and frame.args["cat"] then |
|||
local cat_number |
|||
while true do |
|||
local cat = frame.args["cat" .. (cat_number or "")] |
|||
if not cat then break end |
|||
cat = mw.text.trim(cat) |
|||
if cat ~= "" then |
|||
table.insert(categories, lang:getCanonicalName() .. " " .. cat) |
|||
end |
|||
cat_number = (cat_number or 1) + 1 |
|||
end |
|||
end |
|||
if #categories > 0 then |
|||
table.insert( |
|||
parts, |
|||
require("Module:utilities").format_categories(categories, lang, args["sort"])) |
|||
end |
|||
return table.concat(parts) |
|||
end |
|||
local function get_parsed_part(template, lang, args, terms, i) |
|||
local term = terms[i] |
|||
local alt = args["alt"][i] |
|||
local id = args["id"][i] |
|||
local sc = fetch_script(args["sc"][i]) |
|||
local tr = args["tr"][i] |
|||
local ts = args["ts"][i] |
|||
local gloss = args["t"][i] |
|||
local pos = args["pos"][i] |
|||
local lit = args["lit"][i] |
|||
local g = args["g"][i] |
|||
if not (term or alt or tr or ts) then |
|||
track(template .. "/no term or alt or tr") |
|||
return nil |
|||
else |
|||
return require("Module:links").full_link( |
|||
{ term = term, alt = alt, id = id, lang = lang, sc = sc, tr = tr, |
|||
ts = ts, gloss = gloss, pos = pos, lit = lit, |
|||
genders = g and rsplit(g, ",") or {} |
|||
}, "term", true) |
|||
end |
|||
end |
|||
local function get_parsed_parts(template, lang, args, terms) |
|||
local parts = {} |
|||
-- Find the maximum index among any of the list parameters. |
|||
local maxmaxindex = 0 |
|||
for k, v in pairs(args) do |
|||
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then |
|||
maxmaxindex = v.maxindex |
|||
end |
|||
end |
|||
for index = 1, maxmaxindex do |
|||
table.insert(parts, get_parsed_part(template, lang, args, terms, index)) |
|||
end |
|||
return parts |
|||
end |
|||
-- Implementation of miscellaneous templates such as {{doublet}} that can take |
|||
-- multiple terms. Doesn't handle {{blend}} or {{univerbation}}, which display |
|||
-- + signs between elements and use compound_like in [[Module:compound/templates]]. |
|||
function export.misc_variant_multiple_terms(frame) |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
[2] = {list = true, allow_holes = true}, |
|||
["t"] = {list = true, allow_holes = true, require_index = true}, |
|||
["gloss"] = {list = true, allow_holes = true, require_index = true, alias_of = "t"}, |
|||
["tr"] = {list = true, allow_holes = true, require_index = true}, |
|||
["ts"] = {list = true, allow_holes = true, require_index = true}, |
|||
["g"] = {list = true, allow_holes = true, require_index = true}, |
|||
["id"] = {list = true, allow_holes = true, require_index = true}, |
|||
["alt"] = {list = true, allow_holes = true, require_index = true}, |
|||
["lit"] = {list = true, allow_holes = true, require_index = true}, |
|||
["pos"] = {list = true, allow_holes = true, require_index = true}, |
|||
["sc"] = {list = true, allow_holes = true, require_index = true}, |
|||
["nocap"] = {type = "boolean"}, -- should be processed in the template itself |
|||
["notext"] = {type = "boolean"}, |
|||
["nocat"] = {type = "boolean"}, |
|||
["sort"] = {}, |
|||
} |
|||
local args = require("Module:parameters").process(frame:getParent().args, params) |
|||
local lang = m_languages.getByCode(args[1], 1) |
|||
local parts = {} |
|||
if not args["notext"] then |
|||
table.insert(parts, frame.args["text"]) |
|||
end |
|||
if #args[2] > 0 or #args["alt"] > 0 then |
|||
if not args["notext"] then |
|||
table.insert(parts, " ") |
|||
table.insert(parts, frame.args["oftext"] or "of") |
|||
table.insert(parts, " ") |
|||
end |
|||
local formatted_terms = get_parsed_parts(mw.ustring.lower( |
|||
-- Remove link and convert uppercase to lowercase to get an |
|||
-- approximation of the original template name. |
|||
rsub(rsub(frame.args["text"], "^%[%[.*|", ""), "%]%]$", "")), |
|||
lang, args, args[2]) |
|||
table.insert(parts, require("Module:table").serialCommaJoin(formatted_terms)) |
|||
end |
|||
if not args["nocat"] and frame.args["cat"] then |
|||
local categories = {} |
|||
table.insert(categories, lang:getCanonicalName() .. " " .. frame.args["cat"]) |
|||
table.insert(parts, require("Module:utilities").format_categories(categories, lang, args["sort"])) |
|||
end |
|||
return table.concat(parts) |
|||
end |
|||
-- Implementation of miscellaneous templates such as {{unknown}} that have no |
|||
-- associated terms. |
|||
function export.misc_variant_no_term(frame) |
|||
local params = { |
|||
[1] = {required = true, default = "und"}, |
|||
["title"] = {}, |
|||
["nocap"] = {type = "boolean"}, -- should be processed in the template itself |
|||
["notext"] = {type = "boolean"}, |
|||
["nocat"] = {type = "boolean"}, |
|||
["sort"] = {}, |
|||
} |
|||
if frame.args["title2_alias"] then |
|||
params[2] = {alias_of = "title"} |
|||
end |
|||
local args = require("Module:parameters").process(frame:getParent().args, params) |
|||
local lang = m_languages.getByCode(args[1], 1) |
|||
local parts = {} |
|||
if not args["notext"] then |
|||
table.insert(parts, args["title"] or frame.args["text"]) |
|||
end |
|||
if not args["nocat"] and frame.args["cat"] then |
|||
local categories = {} |
|||
table.insert(categories, lang:getCanonicalName() .. " " .. frame.args["cat"]) |
|||
table.insert(parts, require("Module:utilities").format_categories(categories, lang, args["sort"])) |
|||
end |
|||
return table.concat(parts) |
|||
end |
|||
return export |
Revision as of 02:46, 27 November 2020
- The following documentation is located at Module:etymology/templates/documentation. [edit]
- Useful links: root page • root page’s subpages • links • transclusions • testcases • sandbox
This module generates content for several etymology templates. They include:
{{etyl}}
Also, the following specialized borrowing templates (not including {{bor}}
/{{borrowed}}
itself):
{{learned borrowing}}
{{semi-learned borrowing}}
{{orthographic borrowing}}
{{unadapted borrowing}}
{{calque}}
{{partial calque}}
{{semantic loan}}
{{phono-semantic matching}}
{{transliteration}}
Miscellaneous etymology templates that take a single term parameter:
{{abbrev}}
{{back-formation}}
{{clipping}}
{{ellipsis}}
{{initialism}}
{{rebracketing}}
{{reduplication}}
- ...
Miscellaneous etymology templates that take no term parameter:
{{onomatopoeic}}
{{unknown}}
- ...
Some templates that used to be here but have now been moved to submodules:
- Module:etymology/templates/cognate:
{{cognate}}
,{{noncognate}}
- Module:etymology/templates/derived:
{{derived}}
- Module:etymology/templates/inherited:
{{inherited}}
- Module:etymology/templates/borrowed:
{{borrowed}}
- Module:etymology/templates/doublet:
{{doublet}}
- Module:etymology/templates/descendant:
{{descendant}}
,{{descendants tree}}
local export = {}
local m_languages = require("Module:languages")
local m_etymology = require("Module:etymology")
local rsplit = mw.text.split
local rsubn = mw.ustring.gsub
-- 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)
return require("Module:debug").track(page)
end
local function fetch_script(sc)
if sc then
return require("Module:scripts").getByCode(sc, true)
else
return nil
end
end
function export.etyl(frame)
local params = {
[1] = {required = true, default = "und"},
[2] = {},
["sort"] = {},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local source = m_languages.getByCode(args[1], 1, "allow etym", "allow family")
local lang = args[2]
local sort_key = args["sort"]
-- Empty language means English, but "-" means no language. Yes, confusing...
if not lang then
lang = "en"
elseif lang == "-" then
lang = nil
end
if lang then
lang = m_languages.getByCode(lang, 2)
end
if lang and (lang:getCode() == "la" or lang:getCode() == "nl") then
track("etyl/" .. lang:getCode())
track("etyl/" .. lang:getCode() .. "/" .. source:getCode())
end
return m_etymology.format_etyl(lang, source, sort_key)
end
function export.cognate(frame)
local args = frame:getParent().args
if args.gloss then
track("cognate/gloss param")
end
local params = {
[1] = {required = true, default = "und"},
[2] = {},
[3] = {alias_of = "alt"},
[4] = {alias_of = "t"},
["alt"] = {},
["g"] = {list = true},
["id"] = {},
["lit"] = {},
["pos"] = {},
["t"] = {},
["gloss"] = {alias_of = "t"},
["tr"] = {},
["ts"] = {},
["sc"] = {},
["sort"] = {},
}
args = require("Module:parameters").process(args, params)
local source = m_languages.getByCode(args[1], 1, "allow etym", "allow family")
local sc = fetch_script(args["sc"])
return m_etymology.format_cognate(
{
lang = source,
sc = sc,
term = args[2],
alt = args["alt"],
id = args["id"],
genders = args["g"],
tr = args["tr"],
ts = args["ts"],
gloss = args["t"],
pos = args["pos"],
lit = args["lit"]
},
args["sort"])
end
function export.noncognate(frame)
return export.cognate(frame)
end
local function parse_2_lang_args(frame, has_text, no_family)
local params = {
[1] = {required = true, default = "und"},
[2] = {required = true, default = "und"},
[3] = {},
[4] = {alias_of = "alt"},
[5] = {alias_of = "t"},
["alt"] = {},
["g"] = {list = true},
["gloss"] = {alias_of = "t"},
["id"] = {},
["lit"] = {},
["pos"] = {},
["t"] = {},
["tr"] = {},
["ts"] = {},
["sc"] = {},
["nocat"] = {type = "boolean"},
["sort"] = {},
}
if has_text then
params["notext"] = {type = "boolean"}
params["nocap"] = {type = "boolean"}
end
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = m_languages.getByCode(args[1], 1)
local source = m_languages.getByCode(args[2], 2, "allow etym", not no_family and "allow family")
local sc = fetch_script(args["sc"])
return args, lang, {
lang = source,
sc = sc,
term = args[3],
alt = args["alt"],
id = args["id"],
genders = args["g"],
tr = args["tr"],
ts = args["ts"],
gloss = args["t"],
pos = args["pos"],
lit = args["lit"]
}
end
function export.derived(frame)
local args, lang, term = parse_2_lang_args(frame)
return m_etymology.format_derived(lang, term, args["sort"], args["nocat"], "derived")
end
function export.inherited(frame)
local args, lang, term = parse_2_lang_args(frame, nil, "no family")
return m_etymology.format_inherited(lang, term, args["sort"], args["nocat"])
end
function export.borrowed(frame)
local args, lang, term = parse_2_lang_args(frame)
return m_etymology.format_borrowed(lang, term, args["sort"],
false, true, args["nocat"], "plain")
end
function export.learned_borrowing(frame)
if frame:getParent().args.gloss then
track("learned_borrowing/gloss param")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.format_borrowed(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"], "learned")
end
function export.semi_learned_borrowing(frame)
if frame:getParent().args.gloss then
track("semi_learned_borrowing/gloss param")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.format_borrowed(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"], "semi-learned")
end
function export.orthographic_borrowing(frame)
if frame:getParent().args.gloss then
track("orthographic_borrowing/gloss param")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.format_borrowed(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"], "orthographic")
end
function export.unadapted_borrowing(frame)
if frame:getParent().args.gloss then
track("unadapted_borrowing/gloss param")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.format_borrowed(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"], "unadapted")
end
function export.calque(frame)
local args = frame:getParent().args
-- More informative error message.
if args["etyl lang"] or args["etyl term"] or args["etyl t"] or args["etyl tr"] then
error("{{[[Template:calque|calque]]}} no longer supports parameters beginning with etyl. " ..
"The parameters supported are similar to those used by " ..
"{{[[Template:der|der]]}}, {{[[Template:inh|inh]]}}, " ..
"{{[[Template:bor|bor]]}}. See [[Template:calque/documentation]] for more.")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.calque(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"])
end
function export.partial_calque(frame)
if frame:getParent().args.gloss then
track("partial_calque/gloss param")
end
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.partial_calque(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"])
end
function export.semantic_loan(frame)
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.semantic_loan(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"])
end
function export.psm(frame)
local args, lang, term = parse_2_lang_args(frame, "has text")
return m_etymology.phono_semantic_matching(lang, term, args["sort"],
args["nocap"], args["notext"], args["nocat"])
end
local function qualifier(content)
if content then
return table.concat{
'<span class="ib-brac qualifier-brac">(</span>',
'<span class="ib-content qualifier-content">',
content,
'</span>',
'<span class="ib-brac qualifier-brac">)</span>'
}
end
end
local function add_tooltip(text, tooltip)
return '<span class="desc-arr" title="' .. tooltip .. '">' .. text .. '</span>'
end
local function desc_or_desc_tree(frame, desc_tree)
local params
if desc_tree then
params = {
[1] = {required = true, default = "gem-pro"},
[2] = {required = true, list = "term", allow_holes = true, default = "*fuhsaz"},
["notext"] = { type = "boolean" },
["noalts"] = { type = "boolean" },
["noparent"] = { type = "boolean" },
}
else
params = {
[1] = { required = true, default = "en" },
[2] = { list = "term", allow_holes = true, default = "word" },
["alts"] = { type = "boolean" }
}
end
for k, v in pairs({
[3] = { alias_of = "alt" },
["alt"] = { list = true, allow_holes = true },
[4] = { alias_of = "t" },
-- FIXME, currently all genders refer to first term, for historical reasons
["g"] = { list = true, allow_holes = true },
["gloss"] = { alias_of = "t", list = true, allow_holes = true },
["id"] = { list = true, allow_holes = true },
["lit"] = { list = true, allow_holes = true },
["pos"] = { list = true, allow_holes = true },
["t"] = { list = true, allow_holes = true },
["tr"] = { list = true, allow_holes = true },
["ts"] = { list = true, allow_holes = true },
["sc"] = { list = true, allow_holes = true },
["inh"] = { type = "boolean" },
["partinh"] = { type = "boolean", list = "inh", allow_holes = true, require_index = true },
["bor"] = { type = "boolean" },
["partbor"] = { type = "boolean", list = "bor", allow_holes = true, require_index = true },
["lbor"] = { type = "boolean" },
["partlbor"] = { type = "boolean", list = "lbor", allow_holes = true, require_index = true },
["slb"] = { type = "boolean" },
["partslb"] = { type = "boolean", list = "slb", allow_holes = true, require_index = true },
["der"] = { type = "boolean" },
["partder"] = { type = "boolean", list = "der", allow_holes = true, require_index = true },
["clq"] = { type = "boolean" },
["partclq"] = { type = "boolean", list = "clq", allow_holes = true, require_index = true },
["cal"] = { alias_of = "clq", type = "boolean" },
["partcal"] = { alias_of = "partclq", type = "boolean", list = "cal", allow_holes = true, require_index = true },
["calq"] = { alias_of = "clq", type = "boolean" },
["partcalq"] = { alias_of = "partclq", type = "boolean", list = "calq", allow_holes = true, require_index = true },
["calque"] = { alias_of = "clq", type = "boolean" },
["partcalque"] = { alias_of = "partclq", type = "boolean", list = "calque", allow_holes = true, require_index = true },
["pclq"] = { type = "boolean" },
["partpclq"] = { type = "boolean", list = "pclq", allow_holes = true, require_index = true },
["sml"] = { type = "boolean" },
["partsml"] = { type = "boolean", list = "sml", allow_holes = true, require_index = true },
["unc"] = { type = "boolean" },
["partunc"] = { type = "boolean", list = "unc", allow_holes = true, require_index = true },
["sclb"] = { type = "boolean" },
["nolb"] = { type = "boolean" },
["q"] = {},
["partq"] = { list = "q", allow_holes = true, require_index = true },
["sandbox"] = { type = "boolean" },
}) do
params[k] = v
end
local namespace = mw.title.getCurrentTitle().nsText
local parent_args
if frame.args[1] then
parent_args = frame.args
else
parent_args = frame:getParent().args
end
if parent_args[3] then
track("descendants/arg3")
end
if parent_args[4] then
track("descendants/arg4")
end
local args = require("Module:parameters").process(parent_args, params)
if args.sandbox then
if namespace == "" or namespace == "Reconstruction" then
error("The sandbox module, Module:descendants tree/sandbox, should not be used in entries.")
end
end
local m_desctree
if desc_tree or args["alts"] then
if args.sandbox or require("Module:yesno")(frame.args.sandbox, false) then
m_desctree = require("Module:descendants tree/sandbox")
else
m_desctree = require("Module:descendants tree")
end
end
-- FIXME! Remove this after converting existing instances of multiple genders to a single gender param, comma-separated.
if args["g"].maxindex > 0 then
local genders = {}
for i = 1, args["g"].maxindex do
if args["g"][i] then
table.insert(genders, args["g"][i])
end
end
args["g"] = {table.concat(genders, ",")}
args["g"].maxindex = 1
end
-- Check for any remaining places where g2= might be used for the first term's second gender.
-- (Applies after the FIXME code just above is removed.)
if args["g"].maxindex > args[2].maxindex then
track("descendant/gender-no-term")
end
local lang = args[1]
lang = m_languages.getByCode(lang, 1, "allow etym")
local entryLang = m_languages.getNonEtymological(lang)
if not desc_tree and entryLang:getType() == "family" then
error("Cannot use language family code in [[Template:desc]].")
end
if lang:getCode() ~= entryLang:getCode() then
-- [[Special:WhatLinksHere/Template:tracking/descendant/etymological]]
track("descendant/etymological")
track("descendant/etymological/" .. lang:getCode())
end
local languageName = lang:getCanonicalName()
languageName = mw.ustring.gsub(languageName, "^Proto%-", "")
local label
-- Find the maximum index among any of the list parameters.
local maxmaxindex = 0
for k, v in pairs(args) do
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then
maxmaxindex = v.maxindex
end
end
local function get_arrow(index)
local function val(arg)
if index == 0 then
return args[arg]
else
return args["part" .. arg][index]
end
end
local arrow
if val("bor") then
arrow = add_tooltip("→", "borrowed")
elseif val("lbor") then
arrow = add_tooltip("→", "learned borrowing")
elseif val("slb") then
arrow = add_tooltip("→", "semi-learned borrowing")
elseif val("clq") then
arrow = add_tooltip("→", "calque")
elseif val("pclq") then
arrow = add_tooltip("→", "partial calque")
elseif val("sml") then
arrow = add_tooltip("→", "semantic loan")
elseif val("unc") and not val("der") then
arrow = add_tooltip(">", "inherited")
else
arrow = ""
end
-- allow der=1 in conjunction with bor=1 to indicate e.g. English "pars recta"
-- derived and borrowed from Latin "pars".
if val("der") then
arrow = arrow .. add_tooltip("⇒", "reshaped by analogy or addition of morphemes")
end
if val("unc")then
arrow = arrow .. add_tooltip("?", "uncertain")
end
if arrow ~= "" then
arrow = arrow .. " "
end
return arrow
end
local function get_post_qualifiers(index)
local function val(arg)
if index == 0 then
return args[arg]
else
return args["part" .. arg][index]
end
end
local postqs = {}
if val("inh") then
table.insert(postqs, qualifier("inherited"))
end
if val("lbor") then
table.insert(postqs, qualifier("learned"))
end
if val("slb") then
table.insert(postqs, qualifier("semi-learned"))
end
if val("clq") then
table.insert(postqs, qualifier("calque"))
end
if val("pclq") then
table.insert(postqs, qualifier("partial calque"))
end
if val("sml") then
table.insert(postqs, qualifier("semantic loan"))
end
-- FIXME, should we use the qualifier support in full_link() (in which case the qualifier precedes the term)?
if val("q") then
table.insert(postqs, require("Module:qualifier").format_qualifier(val("q")))
end
if #postqs > 0 then
return " " .. table.concat(postqs, " ")
else
return ""
end
end
local parts = {}
local descendants = {}
local saw_descendants = false
local terms = {}
for i = 1, maxmaxindex do
local term = args[2][i]
local alt = args["alt"][i]
local id = args["id"][i]
local sc = args["sc"][i] and require("Module:scripts").getByCode(args["sc"][i], "sc" .. (i == 1 and "" or i))
local tr = args["tr"][i]
local ts = args["ts"][i]
local gloss = args["t"][i]
local pos = args["pos"][i]
local lit = args["lit"][i]
local g = args["g"][i] and rsplit(args["g"][i], "%s*,%s*") or {}
if i == 1 then
if args["sclb"] then
if sc then
label = sc:getCanonicalName()
elseif not term then
error("When sclb=1, must specify sc= or 2=")
else
label = require("Module:scripts").findBestScript(term, lang):getCanonicalName()
end
else
label = languageName
end
end
local link = ""
if term ~= "-" then
link = require("Module:links").full_link(
{
lang = entryLang,
sc = sc,
term = term,
alt = alt,
id = id,
tr = tr,
ts = ts,
genders = g,
gloss = gloss,
pos = pos,
lit = lit,
},
nil,
true)
elseif ts or gloss or #g > 0 then
-- [[Special:WhatLinksHere/Template:tracking/descendant/no term]]
track("descendant/no term")
link = require("Module:links").full_link(
{
lang = entryLang,
sc = sc,
ts = ts,
gloss = gloss,
genders = g,
},
nil,
true)
link = link
:gsub("<small>%[Term%?%]</small> ", "")
:gsub("<small>%[Term%?%]</small> ", "")
:gsub("%[%[Category:[^%[%]]+ term requests%]%]", "")
else -- display no link at all
-- [[Special:WhatLinksHere/Template:tracking/descendant/no term or annotations]]
track("descendant/no term or annotations")
end
local arrow = get_arrow(i)
local postqs = get_post_qualifiers(i)
local alts
if desc_tree and term and term ~= "-" then
table.insert(terms, term)
descendants[i] = m_desctree.getDescendants(entryLang, term, id, maxmaxindex > 1)
if descendants[i] then
saw_descendants = true
end
end
descendants[i] = descendants[i] or ""
if desc_tree and not args["noalts"] or not desc_tree and args["alts"] then
-- [[Special:WhatLinksHere/Template:tracking/desc/alts]]
track("desc/alts")
alts = m_desctree.getAlternativeForms(entryLang, term)
else
alts = ""
end
local linktext = table.concat{link, alts, postqs}
if not args["notext"] then
linktext = arrow .. linktext
end
if linktext ~= "" then
table.insert(parts, linktext)
end
end
if desc_tree and not saw_descendants then
if #terms == 0 then
error("{{desctree}} invoked but no terms to retrieve descendants from")
elseif #terms == 1 then
error("No Descendants section was found in the entry [[" .. terms[1] ..
"]] under the header for " .. entryLang:getCanonicalName() .. ".")
else
for i, term in ipairs(terms) do
terms[i] = "[[" .. term .. "]]"
end
error("No Descendants section was found in any of the entries " ..
table.concat(terms, ", ") .. " under the header for " .. entryLang:getCanonicalName() .. ".")
end
end
descendants = table.concat(descendants)
if args["noparent"] then
return descendants
end
local initial_arrow = get_arrow(0)
local final_postqs = get_post_qualifiers(0)
local all_linktext = table.concat(parts, ", ") .. final_postqs .. descendants
if args["notext"] then
return all_linktext
elseif args["nolb"] then
return initial_arrow .. all_linktext
else
return table.concat{initial_arrow, label, ":", linktext ~= "" and " " or "", all_linktext}
end
end
function export.descendant(frame)
return desc_or_desc_tree(frame, false) .. require("Module:TemplateStyles")("Module:etymology/style.css")
end
function export.descendants_tree(frame)
return desc_or_desc_tree(frame, true)
end
-- Implementation of miscellaneous templates such as {{back-formation}}, {{clipping}},
-- {{ellipsis}}, {{rebracketing}}, and {{reduplication}} that have a single
-- associated term.
function export.misc_variant(frame)
local params = {
[1] = {required = true, default = "und"},
[2] = {},
[3] = {alias_of = "alt"},
[4] = {alias_of = "t"},
["alt"] = {},
["gloss"] = {alias_of = "t"},
["g"] = {list = true},
["id"] = {},
["lit"] = {},
["pos"] = {},
["t"] = {},
["tr"] = {},
["ts"] = {},
["sc"] = {},
["nocap"] = {type = "boolean"}, -- should be processed in the template itself
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
["sort"] = {},
}
-- |ignore-params= parameter to module invocation specifies
-- additional parameter names to allow in template invocation, separated by
-- commas. They must consist of ASCII letters or numbers or hyphens.
local ignore_params = frame.args["ignore-params"]
if ignore_params then
ignore_params = mw.text.trim(ignore_params)
if not ignore_params:match "^[%w%-,]+$" then
error("Invalid characters in |ignore-params=: " .. ignore_params:gsub("[%w%-,]+", ""))
end
for param in ignore_params:gmatch "[%w%-]+" do
if params[param] then
error("Duplicate param |" .. param
.. " in |ignore-params=: already specified in params")
end
params[param] = {}
end
end
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = m_languages.getByCode(args[1], 1)
local sc = fetch_script(args["sc"])
local parts = {}
if not args["notext"] then
table.insert(parts, frame.args["text"])
end
if args[2] or args["alt"] then
if not args["notext"] then
table.insert(parts, " ")
table.insert(parts, frame.args["oftext"] or "of")
table.insert(parts, " ")
end
table.insert(parts, require("Module:links").full_link(
{
lang = lang,
sc = sc,
term = args[2],
alt = args["alt"],
id = args["id"],
tr = args["tr"],
ts = args["ts"],
genders = args["g"],
gloss = args["t"],
pos = args["pos"],
lit = args["lit"],
},
"term",
true))
end
-- Allow |cat=, |cat2=, |cat3=, etc. They must be sequential. If |cat=
-- is not defined, |cat2= will not be checked. Empty categories are ignored.
local categories = {}
if not args["nocat"] and frame.args["cat"] then
local cat_number
while true do
local cat = frame.args["cat" .. (cat_number or "")]
if not cat then break end
cat = mw.text.trim(cat)
if cat ~= "" then
table.insert(categories, lang:getCanonicalName() .. " " .. cat)
end
cat_number = (cat_number or 1) + 1
end
end
if #categories > 0 then
table.insert(
parts,
require("Module:utilities").format_categories(categories, lang, args["sort"]))
end
return table.concat(parts)
end
local function get_parsed_part(template, lang, args, terms, i)
local term = terms[i]
local alt = args["alt"][i]
local id = args["id"][i]
local sc = fetch_script(args["sc"][i])
local tr = args["tr"][i]
local ts = args["ts"][i]
local gloss = args["t"][i]
local pos = args["pos"][i]
local lit = args["lit"][i]
local g = args["g"][i]
if not (term or alt or tr or ts) then
track(template .. "/no term or alt or tr")
return nil
else
return require("Module:links").full_link(
{ term = term, alt = alt, id = id, lang = lang, sc = sc, tr = tr,
ts = ts, gloss = gloss, pos = pos, lit = lit,
genders = g and rsplit(g, ",") or {}
}, "term", true)
end
end
local function get_parsed_parts(template, lang, args, terms)
local parts = {}
-- Find the maximum index among any of the list parameters.
local maxmaxindex = 0
for k, v in pairs(args) do
if type(v) == "table" and v.maxindex and v.maxindex > maxmaxindex then
maxmaxindex = v.maxindex
end
end
for index = 1, maxmaxindex do
table.insert(parts, get_parsed_part(template, lang, args, terms, index))
end
return parts
end
-- Implementation of miscellaneous templates such as {{doublet}} that can take
-- multiple terms. Doesn't handle {{blend}} or {{univerbation}}, which display
-- + signs between elements and use compound_like in [[Module:compound/templates]].
function export.misc_variant_multiple_terms(frame)
local params = {
[1] = {required = true, default = "und"},
[2] = {list = true, allow_holes = true},
["t"] = {list = true, allow_holes = true, require_index = true},
["gloss"] = {list = true, allow_holes = true, require_index = true, alias_of = "t"},
["tr"] = {list = true, allow_holes = true, require_index = true},
["ts"] = {list = true, allow_holes = true, require_index = true},
["g"] = {list = true, allow_holes = true, require_index = true},
["id"] = {list = true, allow_holes = true, require_index = true},
["alt"] = {list = true, allow_holes = true, require_index = true},
["lit"] = {list = true, allow_holes = true, require_index = true},
["pos"] = {list = true, allow_holes = true, require_index = true},
["sc"] = {list = true, allow_holes = true, require_index = true},
["nocap"] = {type = "boolean"}, -- should be processed in the template itself
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
["sort"] = {},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = m_languages.getByCode(args[1], 1)
local parts = {}
if not args["notext"] then
table.insert(parts, frame.args["text"])
end
if #args[2] > 0 or #args["alt"] > 0 then
if not args["notext"] then
table.insert(parts, " ")
table.insert(parts, frame.args["oftext"] or "of")
table.insert(parts, " ")
end
local formatted_terms = get_parsed_parts(mw.ustring.lower(
-- Remove link and convert uppercase to lowercase to get an
-- approximation of the original template name.
rsub(rsub(frame.args["text"], "^%[%[.*|", ""), "%]%]$", "")),
lang, args, args[2])
table.insert(parts, require("Module:table").serialCommaJoin(formatted_terms))
end
if not args["nocat"] and frame.args["cat"] then
local categories = {}
table.insert(categories, lang:getCanonicalName() .. " " .. frame.args["cat"])
table.insert(parts, require("Module:utilities").format_categories(categories, lang, args["sort"]))
end
return table.concat(parts)
end
-- Implementation of miscellaneous templates such as {{unknown}} that have no
-- associated terms.
function export.misc_variant_no_term(frame)
local params = {
[1] = {required = true, default = "und"},
["title"] = {},
["nocap"] = {type = "boolean"}, -- should be processed in the template itself
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
["sort"] = {},
}
if frame.args["title2_alias"] then
params[2] = {alias_of = "title"}
end
local args = require("Module:parameters").process(frame:getParent().args, params)
local lang = m_languages.getByCode(args[1], 1)
local parts = {}
if not args["notext"] then
table.insert(parts, args["title"] or frame.args["text"])
end
if not args["nocat"] and frame.args["cat"] then
local categories = {}
table.insert(categories, lang:getCanonicalName() .. " " .. frame.args["cat"])
table.insert(parts, require("Module:utilities").format_categories(categories, lang, args["sort"]))
end
return table.concat(parts)
end
return export