Module:etymology
The etymology module provides functionality for various etymology templates:
{{abbreviation}}
,{{abbr}}
{{affix}}
,{{aff}}
{{back-formation}}
,{{back-form}}
,{{bf}}
{{blend}}
{{borrowed}}
,{{borrow}}
,{{bor}}
{{calque}}
,{{clq}}
,{{cal}}
{{clipping}}
{{contraction}}
,{{contr}}
{{deadjectival}}
,{{deadj}}
{{denominal}}
,{{den}}
{{derived}}
,{{derive}}
,{{der}}
{{deverbal}}
,{{dev}}
{{doublet}}
,{{dbt}}
{{ellipsis}}
{{grammaticalisation}}
,{{gram}}
{{inherited}}
,{{inherit}}
,{{inh}}
{{initialism}}
,{{init}}
{{learned borrowing}}
,{{lbor}}
{{onomatopoeic}}
,{{onom}}
{{orthographic borrowing}}
,{{obor}}
{{phono-semantic matching}}
,{{psm}}
{{rebracketing}}
,{{rbr}}
{{reduplication}}
,{{rdp}}
{{semantic loan}}
,{{sl}}
{{transliteration}}
,{{translit}}
{{uncertain}}
,{{unc}}
{{univerbation}}
,{{univ}}
{{unknown}}
,{{unk}}
local export = {}
local m_inline = require("Module:inline")
local m_languages = require("Module:languages")
local m_links = require("Module:links")
local m_parameters = require("Module:parameters")
local new_pos_data = {
["adjective"] = {
categories = {"adjectivisations"},
},
["noun"] = {
categories = {"nominalisations"},
},
["verb"] = {
categories = {"verbalisations"},
},
}
local new_pos_aliases = {
["adj"] = "adjective",
["n"] = "noun",
["v"] = "verb",
}
local no_term_params = {
[1] = {required = true},
["nocap"] = {type = "boolean"},
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
}
local no_term_data = {
["onomatopoeic"] = {
categories = {"onomatopoeias"},
text = true,
},
["unknown"] = {
categories = {"terms with unknown etymologies"},
text = function(nocap) return (nocap and "u" or "U") .. "nknown" end,
},
}
local single_term_params = {
[1] = {required = true},
[2] = {required = true},
[3] = {alias_of = "alt"},
[4] = {alias_of = "t"},
["alt"] = {},
["t"] = {},
["pos"] = {},
["newpos"] = {},
["nocap"] = {type = "boolean"},
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
}
local single_term_data = {
["abbreviation"] = {
text = true,
categories = {"abbreviations"}
},
["back-formation"] = {
text = true,
categories = {"back-formations"}
},
["clipping"] = {
text = true,
categories = {"clippings"},
},
["deadjectival"] = {
text = true,
categories = {"deadjectivals"},
},
["denominal"] = {
text = true,
categories = {"denominals"},
},
["deverbal"] = {
text = true,
categories = {"deverbals"},
},
["doublet"] = {
text = true,
categories = {"doublets"},
},
["ellipsis"] = {
text = true,
categories = {"ellipses"},
},
["initialism"] = {
text = true,
categories = {"initialisms"},
},
["rebracketing"] = {
text = true,
categories = {"rebracketings"},
},
["reduplication"] = {
text = true,
categories = {"reduplications"},
},
}
local derived_term_params = {
[1] = {required = true},
[2] = {required = true},
[3] = {required = true},
[4] = {alias_of = "alt"},
[5] = {alias_of = "t"},
["alt"] = {},
["t"] = {},
["pos"] = {},
["nocap"] = {type = "boolean"},
["notext"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
}
local derived_term_data = {
["borrowed"] = {
categories = {"terms borrowed from"},
},
["calque"] = {
text = true,
categories = {"terms calqued from"},
},
["derived"] = {
categories = {"terms derived from"},
},
["inherited"] = {
categories = {"terms inherited from"},
},
["learned borrowing"] = {
text = true,
categories = {"terms borrowed from", "learned borrowings from"},
},
["orthographic borrowing"] = {
text = true,
categories = {"terms borrowed from", "orthographic borrowings from"},
},
["semantic loan"] = {
text = true,
categories = {"terms derived from", "semantic loans from"},
},
["phono-semantic matching"] = {
text = true,
categories = {"terms derived from", "phono-semantic matchings from"},
},
["transliteration"] = {
text = true,
categories = {"terms derived from", "transliterations of"},
},
}
local affix_params = {
[1] = {required = true},
[2] = {list = true},
["t"] = {list = true, allow_holes = true},
["l"] = {list = true, allow_holes = true},
["alt"] = {list = true, allow_holes = true},
["pos"] = {list = true, allow_holes = true},
["noaff"] = {list = true, allow_holes = true, type = "boolean"},
["notext"] = {type = "boolean"},
["nocap"] = {type = "boolean"},
["nocat"] = {type = "boolean"},
}
local affix_data = {
["affix"] = {},
["surface analysis"] = {
text = function(nocap) return (nocap and "b" or "B") .. "y [[Appendix:Glossary#surface analysis|surface analysis]], " end
}
}
local affix_delimiter = {
["-"] = true,
["·"] = true,
}
local function is_infix(word)
return affix_delimiter[mw.ustring.sub(word, 1, 1)] and affix_delimiter[mw.ustring.sub(word, -1)]
end
local function is_prefix(word)
return affix_delimiter[mw.ustring.sub(word, -1)]
end
local function is_suffix(word)
return affix_delimiter[mw.ustring.sub(word, 1, 1)]
end
local function format_etymology(out, categories)
for _, category in ipairs(categories) do
out = out .. "[[Category:" .. category .. "]]"
end
return out
end
local function format_solo_text(label, text_data, nocap_arg)
if not text_data then return "" end
if type(text_data) == "function" then return text_data(nocap_arg) end
return "[[Appendix:Glossary#" .. label .. "|" .. (nocap_arg and label or mw.ustring.gsub(label, "^%l", string.upper)) .. "]]"
end
local function format_prefixed_text(label, text_data, nocap_arg)
if not text_data then return "" end
if type(text_data) == "function" then return text_data(nocap_arg) end
local prep = "of"
if label == "back-formation" then prep = "from" end
return "[[Appendix:Glossary#" .. label .. "|" .. (nocap_arg and label or mw.ustring.gsub(label, "^%l", string.upper)) .. "]] " .. prep .. " "
end
local function hydrate_category(category, language_to, language_from, newpos)
local new_category = language_to.name .. " " .. category
if language_from then new_category = new_category .. " " .. language_from.name end
return new_category
end
local function hydrate_categories(categories, language_to, language_from, newpos)
local new_categories = {}
for i, category in ipairs(categories) do
new_categories[i] = language_to.name .. " " .. category .. (language_from and (" " .. language_from.name) or "")
end
if newpos then
newpos = new_pos_aliases[newpos] or newpos
local newpos_data = new_pos_data[newpos]
for _, category in ipairs(newpos_data["categories"]) do table.insert(new_categories, language_from .. " " .. category) end
end
return new_categories
end
local function no_term_etymology(template, frame)
local data, args = no_term_data[template], m_parameters.process(frame:getParent().args, no_term_params)
local out, categories = "", {}
local language = m_languages.get_by_code(args[1])
if not args["nocat"] then categories = hydrate_categories(data["categories"], language) end
if not args["notext"] then out = format_solo_text(template, data["text"], args["nocap"]) end
return format_etymology(out, categories)
end
local function single_term_etymology(template, frame)
local data, args = single_term_data[template], m_parameters.process(frame:getParent().args, single_term_params)
local out, categories = "", {}
local language = m_languages.get_by_code(args[1])
if not args["notext"] then out = out .. format_prefixed_text(template, data["text"], args["nocap"]) end
out = out .. m_links.full_link({
term = args[2],
language = language,
alt = args["alt"],
gloss = args["t"],
pos = args["pos"],
nobold = true,
}, "term")
if not args["nocat"] then categories = hydrate_categories(data["categories"], language, nil, args["newpos"]) end
return format_etymology(out, categories)
end
local function derived_term_etymology(template, frame)
local data, args = derived_term_data[template], m_parameters.process(frame:getParent().args, derived_term_params)
local out, categories = "", {}
local language_to = m_languages.get_by_code(args[1])
local language_from = m_languages.get_by_code(args[2])
if (not args["notext"]) and (not data["silent"]) then out = out .. format_prefixed_text(template, data["text"], args["nocap"]) end
out = out .. m_links.full_link({
term = args[3],
language = language_from,
alt = args["alt"],
gloss = args["t"],
pos = args["pos"],
showlanguage = true,
nobold = true,
}, "term")
if not args["nocat"] then categories = hydrate_categories(data["categories"], language_to, language_from) end
return format_etymology(out, categories)
end
local function affix_etymology(template, frame)
local data, args = affix_data[template], m_parameters.process(frame:getParent().args, affix_params)
local pre_out, categories = {}, {}
local language_to = m_languages.get_by_code(args[1])
local n_parts, n_affixes = 0, 0
for i, term in ipairs(args[2]) do
local i_term, i_args = m_inline.parse(term)
n_parts = n_parts + 1
local language_from = nil
if args["l"][i] or i_args["l"] then language_from = m_languages.get_by_code(args["l"][i] or i_args["l"]) end
local cite_term = i_term
if (language_from and language_from.proto) or ((not language_from) and language_to.proto) then cite_term = "*" .. cite_term end
if not args["nocat"] then
if args["noaff"][i] then
-- this is a marked non-affix, don't let it be classified as one!
elseif language_from then
table.insert(categories, language_to.name .. " terms derived from " .. language_from.name)
if is_infix(term) or is_prefix(term) or is_suffix(term) then n_affixes = n_affixes + 1 end
elseif is_infix(term) then
table.insert(categories, language_to.name .. " terms infixed with " .. cite_term)
n_affixes = n_affixes + 1
elseif is_prefix(term) then
table.insert(categories, language_to.name .. " terms prefixed with " .. cite_term)
n_affixes = n_affixes + 1
elseif is_suffix(term) then
table.insert(categories, language_to.name .. " terms suffixed with " .. cite_term)
n_affixes = n_affixes + 1
end
end
table.insert(pre_out, m_links.full_link({
term = i_term,
language = language_from or language_to,
alt = args["alt"][i] or i_args["alt"],
gloss = args["t"][i] or i_args["t"],
pos = args["pos"][i] or i_args["pos"],
showlanguage = (language_from and true),
nobold = true,
}, "term"))
end
if (not args["nocat"]) and (n_parts > 1 and n_affixes == 0) then
table.insert(categories, language_to.name .. " compound terms")
end
local out = table.concat(pre_out, " + ")
if not args["notext"] then
out = format_prefixed_text(template, data["text"], args["nocap"]) .. out
end
return format_etymology(out, categories)
end
function export.show(frame)
local template = frame.args[1]
if no_term_data[template] then return no_term_etymology(template, frame) end
if single_term_data[template] then return single_term_etymology(template, frame) end
if derived_term_data[template] then return derived_term_etymology(template, frame) end
if affix_data[template] then return affix_etymology(template, frame) end
error("No such sub-template type is defined!")
end
return export