Module:etymon
- පහත දැක්වෙන උපදෙස්, Module:etymon/documentation හි පිහිටා ඇත. [සංස්කරණය] Categories were auto-generated by Module:documentation. [edit]
- ප්රයෝජනවත් සබැඳි: උප පිටු ලැයිස්තුව • සබැඳි • transclusions • testcases • sandbox
This module is used by {{etymon}}
. Currently, it's able to generate an etymology tree, but more features will be added soon.
local export = {}
local m_languages = require("Module:languages")
local m_templateparser = require("Module:template parser")
--Given a language code, return the full code.
local function getCode(langcode)
return m_languages.getByCode(langcode, true, true):getFullCode()
end
--Given a full code and entry name, return the Wiktionary page title.
local function pageName(langcode, entry)
--TODO: is there a better way?
if string.sub(entry, 1, 1) == "*" then
local langname = m_languages.getByCode(langcode, true, true):getCanonicalName()
entry = m_languages.getByCode(langcode, true, true):makeEntryName(entry)
entry = "Reconstruction:" .. langname .. "/" .. string.sub(entry, 2, #entry)
return entry
else
return m_languages.getByCode(langcode, true, true):makeEntryName(entry)
end
end
--Given an etymon param, return its parts.
local function getParts(langParam, etymonParam, normalized)
local etymonLang, etymonPage, etymonId
if select(2, string.gsub(etymonParam, ">", "")) == 1 then
--Fill in langcode if none is provided.
etymonPage, etymonId = etymonParam:match("([^>]+)>([^>]+)")
etymonLang = langParam
else
etymonLang, etymonPage, etymonId = etymonParam:match("([^>]+)>([^>]+)>([^>]+)")
end
if normalized then
etymonLang = getCode(etymonLang)
etymonPage = pageName(etymonLang, etymonPage)
end
return etymonLang, etymonPage, etymonId
end
local paramsOf = {}
--Given an etymon, scrape the page and get its parameters.
--This function returns either: a table of the params, "missing", "redlink", or "nolink"
local function getParams(langParam, etymonParam)
--Get normalized parts of the etymon parameter.
local etymonLang, etymonPage, etymonId = getParts(langParam, etymonParam, true)
--"?" is a special value that unlinks the page.
if etymonId == "?" then
return "nolink"
end
--Find the parameters by scraping etymonPage.
--Store data in the paramsOf[] table to save time in case the same etymon is accessed again.
--The key is a normalized version of etymonParam.
local key = etymonLang .. ">" .. etymonPage .. ">" .. etymonId
if paramsOf[key] == nil then
local pageContent = mw.title.new(etymonPage):getContent()
if pageContent == nil then
paramsOf[key] = "redlink"
else
--Find the template on the page.
for name, templateArgs, _, _ in m_templateparser.findTemplates(pageContent) do
if name == "etymon" then
--Might as well store whatever we find along the way to potentially save time later.
paramsOf[templateArgs[1] .. ">" .. etymonPage .. ">" .. templateArgs["id"]] = templateArgs
if templateArgs[1] == etymonLang and templateArgs["id"] == etymonId then
--This "break" saves time only if etymonPage is only ever accessed once.
--Since this is usually true, it is probably beneficial overall.
break
end
end
end
--If scraping did not produce anything, the template must be missing from the page.
if paramsOf[key] == nil then
paramsOf[key] = "missing"
end
end
end
return paramsOf[key]
end
-- [tag]: {abbreviation, glossary anchor}
local labelDict = {
["from"] = false,
["inh"] = false,
["af"] = false,
["bor"] = {"bor.", "loanword"},
["lbor"] = {"lbor.", "learned_borrowing"},
["der"] = {"der.", "derived_terms"},
["calque"] = {"calq.", "calque"},
["influence"] = {"influ.", "contamination"}
}
--Keep track of what's already been added to the tree and the depth reached.
--Use the normalized etymon parameters as the key.
local alreadySeen = {}
--This function takes an etymon and recursively builds a tree to display in an entry.
local function etyTree(currTitle, currLang, args, isTopLevel, isUncertain, label)
local maxDepth = 0
local subtree, subtreeDepth, etymonLang, etymonPage, etymonParams
local subtrees = {}
local normLang = getCode(currLang)
local normTitle = pageName(currLang, currTitle)
local key = normLang .. ">" .. normTitle .. ">" .. args["id"]
local derType, confidence, ignoreEtymons = "from", "conf", false
--If the entry has already been included in the tree, then don't process it again.
if alreadySeen[key] == nil then
--Loop over each parameter in the current template.
--for _, param in ipairs(args) do
for i, param in ipairs(args) do
if i > 1 and string.match(param, ">") and not ignoreEtymons then
--We want to display the unnormalized language and page title.
--We can't use args[1] here because that would give the normalized language code.
etymonLang, etymonPage, _ = getParts(currLang, param, false)
--Scrape the page and get the parameters.
etymonParams = getParams(currLang, param)
--Check if the function returned an error code.
if type(etymonParams) == "table" then
--Recurse into the etymon and append its tree to the list of subtrees.
subtree, subtreeDepth = etyTree(etymonPage, etymonLang, etymonParams, false, confidence == "unc", derType)
table.insert(subtrees, subtree)
maxDepth = math.max(maxDepth, subtreeDepth)
end
elseif i > 1 then
--Reached a keyword.
if param == "conf" or param == "unc" then
confidence = param
elseif labelDict[param] ~= nil then
ignoreEtymons = false
confidence = "conf"
derType = param
elseif param == "afeq" then
ignoreEtymons = true
else
error("Received unknown keyword: " .. param)
end
end
end
--Add the page to alreadySeen.
alreadySeen[key] = true
end
--Create term block.
local link
if isTopLevel then
link = mw.getCurrentFrame():expandTemplate{title="m+", args={currLang, "", "'''" .. currTitle .. "'''", ["tr"] = m_languages.getByCode(currLang, true, true):transliterate(currTitle)}}
else
link = mw.getCurrentFrame():expandTemplate{title="m+", args={currLang, currTitle, ["id"] = args["id"]}}
end
--Create tree.
local tree = "<div style=\"display:inline;vertical-align:bottom;position:relative;margin-left:4px;margin-right:4px\"><p style=\"margin-top:8px;margin-bottom:8px;display:inline-block;position:relative;z-index:2;padding:5px 10px;background-color:#fffbf2;border:1px solid #ccc;border-radius:4px\">" .. link .. "</p>"
--Add a short top connector if multiple subtrees exist.
if #subtrees >= 2 then
tree = tree .. "<span style=\"position:absolute;left:0;right:50%;height:36px;border-right:2px solid #9e9e9e\"></span>"
end
--Add derivation and uncertainty labels.
if (label ~= "" and labelDict[label] ~= false) or isUncertain then
tree = tree .. "<span style=\"position:absolute;z-index:1;left:50%;transform:translate(-50%);top:calc(100% + 8.5px);border-radius:2px;background-color:rgba(234,255,255,0.85);font-size:12px;height:10px;line-height:10px\">"
if label ~= "" and labelDict[label] ~= false then
tree = tree .. "<span>''[[Appendix:Glossary#" .. labelDict[label][2] .. "|<span style=\"color:black\">" .. labelDict[label][1] .. "</span>]]''</span>"
if isUncertain then
--Add uncertainty label next to the derivation label.
tree = tree .. "<span style=\"position:absolute;left:calc(100% + 2px);top:50%;transform:translate(0,-48%);font-size:10px;border-radius:2px;background-color:rgba(255,224,240,0.85);padding:1px 2px\"><span class=\"desc-arr\" title=\"uncertain\"><b>?</b></span></span>"
end
elseif isUncertain then
--Add uncertainty label in the middle.
tree = tree .. "<span style=\"position:absolute;left:50%;top:50%;transform:translate(calc(-50% - 1px),-48%);font-size:10px;border-radius:2px;background-color:rgba(255,224,240,0.85);padding:1px 2px\"><span class=\"desc-arr\" title=\"uncertain\"><b>?</b></span></span>"
end
tree = tree .. "</span>"
end
tree = tree .. "</div>"
--Add line break if parents exist.
if #subtrees >= 1 then
tree = "<br>" .. tree
end
--Append subtrees. For cleaner HTML, only add text-align:center div when necessary.
local subtreeString = ""
if #subtrees == 1 then
--Add a long bottom connector to the subtree.
--Use string.sub() to insert it right before the </div>, which is a little hacky.
subtreeString = string.sub(subtrees[1], 1, string.len(subtrees[1])-6) .. "<span style=\"position:absolute;right:50%;top:0;height:50px;border-right:2px solid #9e9e9e\"></span></div>"
elseif #subtrees >= 2 then
for i,v in ipairs(subtrees) do
if i == 1 then
--Add left connector.
v = v .. "<span style=\"position:absolute;left:calc(50% - 2px);right:-20px;top:calc(100% - 9px);bottom:0;border-bottom:2px solid #9e9e9e;border-left:2px solid #9e9e9e;border-bottom-left-radius:4px\"></span>"
elseif i == #subtrees then
--Add right connector.
v = v .. "<span style=\"position:absolute;left:-20px;right:50%;top:calc(100% - 9px);bottom:0;border-bottom:2px solid #9e9e9e;border-right:2px solid #9e9e9e;border-bottom-right-radius:4px\"></span>"
else
--Add middle connector.
v = v .. "<span style=\"position:absolute;left:-20px;right:-20px;top:calc(100% - 9px);bottom:0;border-bottom:2px solid #9e9e9e\"></span>"
end
subtreeString = subtreeString .. "<div style=\"position:relative;display:inline-block;text-align:center\">" .. v .. "</div>"
end
end
tree = subtreeString .. tree
--Add outer divs.
if isTopLevel then
tree = "<div style=\"flex-grow:1;overflow:auto\"><div style=\"all:initial;font-family:sans-serif;color:black;white-space:nowrap;line-height:1.1;display:inline-block;text-align:center\">" .. tree .. "</div></div>"
end
return tree, maxDepth + 1
end
function export.main(frame)
local args = frame:getParent().args
local langcode = args[1]
--The `title` parameter is used for overriding the page title.
local title = args["title"]
if args["title"] == nil then
title = tostring(mw.title.getCurrentTitle())
end
--Add anchor to output.
local output = {"<ul id=\"" .. m_languages.getByCode(langcode, true, true):getCanonicalName() .. ":_" .. args["id"] .. "\"></ul>"}
local currNode = langcode .. ">" .. title .. ">" .. args["id"]
paramsOf[currNode] = args
--Insert tree.
if args["tree"] ~= nil then
local tree, _ = etyTree(title, langcode, args, true, false, "")
table.insert(output, frame:expandTemplate{title="box-top", args={"Etymology tree"}})
table.insert(output, tree)
table.insert(output, frame:expandTemplate{title="box-bottom"})
end
return table.concat(output)
end
return export