Module:category tree/families
Documentation for this module may be created at Module:category tree/families/doc
local raw_categories = {}
local raw_handlers = {}
local concat = table.concat
local insert = table.insert
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["All language families"] = {
topright = "{{commonscat|Languages by family}}\n{{wp|Language family,List of language families}}",
description = "This category lists all [[language family|language families]].",
parents = {"Fundamental"},
}
raw_categories["Languages by family"] = {
topright = "{{commonscat|Languages by family}}\n{{wp|Language family,List of language families}}",
description = "This category contains all languages categorized hierarchically according to the [[language family]] they belong to.",
additional = "Only top-level language families are shown here. For a full list of all language families, see [[:Category:All language families]] or [[Wiktionary:List of families]].",
parents = {
{name = "All languages", sort = " "},
{name = "All language families", sort = " "},
},
}
raw_categories["Unassigned languages"] = {
description = "Languages that have not yet been assigned to any family by Wiktionary editors, usually due to oversight.",
additional = [=[This should be distinguished from:
* [[:Category:Unclassifiable languages]] (languages that cannot be confidently assigned to any family, typically because the language is extinct or unresearched and has little available data on it);
* [[:Category:Language isolates]] (where there is general agreement that the language has no relatives); and
* [[:Category:Languages of disputed affiliation]] (languages where there is no consensus concerning which family, if any, they belong to).]=],
parents = {
{name = "Languages by family", sort = "*"},
"All language families",
},
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
local function family_is_not_a_family(fam)
if not fam then
return false
elseif fam:getCode() == "qfa-not" then
return true
else
return family_is_not_a_family(fam:getFamily())
end
end
local function family_has_no_category(fam)
local famcode = fam:getCode()
if famcode == "paa" then
return false -- Papuan languages are not a family but have a category
elseif famcode == "qfa-iso" or famcode == "qfa-not" then
return true
else
local parfam = fam:getFamily()
if parfam and parfam:getCode() == "qfa-not" then
-- Constructed languages, sign languages, etc.; no category for them
return true
end
end
return false
end
-- Currently all Papuan families begin with "paa" or "ngf",
local function family_is_papuan(fam)
local famcode = fam:getCode()
return famcode ~= "paa" and (famcode:find("^paa") or famcode:find("^ngf"))
end
local function infobox(fam)
local ret = {}
insert(ret, "<table class=\"wikitable\">\n")
insert(ret, "<tr>\n<th colspan=\"2\" class=\"plainlinks\">[//en.wiktionary.org/w/index.php?title=Module:families/data&action=edit Edit family data]</th>\n</tr>\n")
insert(ret, "<tr>\n<th>Canonical name</th><td>" .. fam:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = fam:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, "<tr>\n<th>Other names</th><td><ul>" .. concat(names, "\n") .. "</ul></td>\n</tr>\n")
end
end
local aliases = fam:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, "<tr>\n<th>Aliases</th><td><ul>" .. concat(names, "\n") .. "</ul></td>\n</tr>\n")
end
end
local varieties = fam:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, "<li><dl><dt>" .. first_var .. "</dt>\n<dd><ul>" .. concat(subvars, "\n") .. "</ul></dd></dl></li>")
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, "<tr>\n<th>Varieties</th><td><ul>" .. concat(names, "\n") .. "</ul></td>\n</tr>\n")
end
end
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Family code]]</th><td><code>" .. fam:getCode() .. "</code></td>\n</tr>\n")
insert(ret, "<tr>\n<th>[[w:Proto-language|Common ancestor]]</th><td>")
local protoLanguage = fam:getProtoLanguage()
if protoLanguage then
insert(ret, "[[:Category:" .. protoLanguage:getCategoryName() .. "|" .. protoLanguage:getCanonicalName() .. "]]")
else
insert(ret, "none")
end
insert(ret, "</td>\n")
insert(ret, "\n</tr>\n")
local parent = fam:getFamily()
if not parent then
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Parent family]]</th>\n<td>")
insert(ret, "unassigned")
elseif parent:getCode() == "qfa-not" then
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Parent family]]</th>\n<td>")
insert(ret, "not a family")
else
local chain = {}
while parent do
if family_has_no_category(parent) then
break
end
insert(chain, "[[:Category:" .. parent:getCategoryName() .. "|" .. parent:getCanonicalName() .. "]]")
parent = parent:getFamily()
end
if #chain == 0 then
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Parent family]]</th>\n<td>")
insert(ret, "no parents")
else
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Parent famil"
.. (#chain == 1 and "y" or "ies") .. "]]</th>\n<td>")
for i = #chain, 1, -1 do
insert(ret, "<ul><li>" .. chain[i])
end
insert(ret, string.rep("</li></ul>", #chain))
end
end
insert(ret, "</td>\n</tr>\n")
if fam:getWikidataItem() and mw.wikibase then
local link = '[' .. mw.wikibase.getEntityUrl(fam:getWikidataItem()) .. ' ' .. fam:getWikidataItem() .. ']'
insert(ret, "<tr><th>Wikidata</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local additional_information = {
["qfa-dis"] = "These are languages where there is no consensus concerning which family, if any, they belong to.",
["qfa-iso"] = "These are languages where there is general agreement that the language has no known relatives.",
["qfa-mix"] = "A [[mixed language]] is a language which is composed of two different languages.",
["qfa-unc"] = "These are languages that cannot be confidently assigned to a family due to lack of sufficient linguistic data. " ..
"They are also commonly called {{w|unclassified language|unclassified languages}}, but this is ambiguous between " ..
"languages that cannot be classified (due to insufficient data) and those that merely have not been classified " ..
"(due to insufficient research).",
}
local preceding_information = {
["qfa-dis"] = "{{also|Category:Unclassifiable languages|Category:Unassigned languages|Category:Language isolates}}",
["qfa-iso"] = "{{also|Category:Languages of disputed affiliation|Category:Unclassifiable languages|Category:Unassigned languages}}",
["qfa-unc"] = "{{also|Category:Languages of disputed affiliation|Category:Unassigned languages|Category:Language isolates}}",
["qfa-mix"] = "{{also|Category:Creole or pidgin languages}}",
["crp"] = "{{also|Category:Mixed languages}}",
}
local specially_named_families = {
["Languages of disputed affiliation"] = "qfa-dis",
["Language isolates"] = "qfa-iso",
}
local specially_named_family_sort_keys = {
["Languages of disputed affiliation"] = "Disputed affiliation",
["Language isolates"] = "Isolate",
}
insert(raw_handlers, function(data)
local family = require("Module:families").getByCategoryName(data.category)
if not family then
local special_code = specially_named_families[data.category]
if special_code then
family = require("Module:families").getByCode(special_code)
if not family then
error(("Internal error: Family code '%s' is an invalid family code."):format(special_code))
end
end
end
if not family then
return nil
end
local parent_fam = family:getFamily()
local first_parent, parent_sort_key, first_parent_sort_key
if not parent_fam or family_has_no_category(parent_fam) then
first_parent = "Languages by family"
parent_sort_key = specially_named_family_sort_keys[data.category]
first_parent_sort_key = "*" .. (parent_sort_key or "")
else
first_parent = parent_fam:getCategoryName()
end
local description, additional = "", ""
local topright
local preceding = preceding_information[family:getCode()]
local additional_preface = additional_information[family:getCode()]
if additional_preface then
additional_preface = additional_preface .. "\n\n"
else
additional_preface = ""
end
if family_is_not_a_family(family) then
additional_preface = additional_preface ..
"This is a pseudo-family, used for grouping purposes but not forming a linguistically valid [[clade]] " ..
"(i.e. a set of linguistically related languages descending from a common parent).\n\n" ..
"Information about this family:\n\n"
else
additional_preface = "Information about " .. family:getCanonicalName() .. ":\n\n"
end
if not data.called_from_inside then
topright = {}
local wikipedia_art = family:getWikipediaArticle("noCategoryFallback")
if wikipedia_art then
insert(topright, "{{wp|" .. wikipedia_art .. "}}")
end
local commons_cat = family:getCommonsCategory()
if commons_cat then
insert(topright, "{{commonscat|" .. commons_cat:gsub("^Category:", "") .. "}}")
end
topright = #topright > 0 and concat(topright, "\n") or nil
description = "This is the main category of the '''" .. family:getDisplayForm() .. "'''."
additional = additional_preface .. infobox(family)
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").print_children,
family:getCode(), {
protolanguage_under_family = true,
must_have_descendants = true
})
if ok then
if tree_of_descendants then
additional = additional .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
additional = additional .. "\n\n" .. ucfirst(family:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
local parents = {
{name = first_parent, sort = first_parent_sort_key},
{name = "All language families", sort = parent_sort_key},
}
if parent_fam and parent_fam:getCode() == "sgn" then
insert(parents, "All sign languages")
end
if family_is_papuan(family) then
insert(parents, "Papuan languages")
end
return {
preceding = preceding,
topright = topright,
description = description,
additional = additional,
parents = parents,
breadcrumb = family:getCanonicalName(),
can_be_empty = true,
}
end)
return {RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers}