ویکیفەرھەنگ ckbwiktionary https://ckb.wiktionary.org/wiki/%D9%88%DB%8C%DA%A9%DB%8C%D9%81%DB%95%D8%B1%DA%BE%DB%95%D9%86%DA%AF:%D8%AF%DB%95%D8%B3%D8%AA%D9%BE%DB%8E%DA%A9 MediaWiki 1.47.0-wmf.15 case-sensitive میدیا تایبەت وتووێژ بەکارھێنەر لێدوانی بەکارھێنەر ویکیفەرھەنگ لێدوانی ویکیفەرھەنگ پەڕگە وتووێژی پەڕگە میدیاویکی وتووێژی میدیاویکی داڕێژە وتووێژی داڕێژە یارمەتی وتووێژی یارمەتی پۆل وتووێژی پۆل TimedText TimedText talk مۆدیوول لێدوانی مۆدیوول Event Event talk مۆدیوول:category tree 828 19 36931 36784 2026-08-18T00:04:03Z Ghybu 12 بەپێی زمان (by language) 36931 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local category_tree_submodule_prefix = "Module:category tree/" local category_tree_styles_css = "Module:category tree/styles.css" local m_str_utils = require("Module:string utilities") local m_template_parser = require("Module:template parser") local m_utilities = require("Module:utilities") local ceil = math.ceil local class_else_type = m_template_parser.class_else_type local concat = table.concat local deep_copy = require("Module:table").deepCopy local full_url = mw.uri.fullUrl local insert = table.insert local is_callable = require("Module:fun").is_callable local log10 = math.log10 or require("Module:math").log10 local new_title = mw.title.new local pages_in_category = mw.site.stats.pagesInCategory local parse = m_template_parser.parse local remove_comments = require("Module:string/removeComments") local sort = table.sort local split = m_str_utils.split local string_compare = require("Module:string/compare") local trim = m_str_utils.trim local uupper = m_str_utils.upper local yesno = require("Module:yesno") local current_frame = mw.getCurrentFrame() local current_title = mw.title.getCurrentTitle() local namespace = current_title.namespace local poscatboiler_subsystem = "poscatboiler" local extra_args_error = "Extra arguments to {{((}}auto cat{{))}} are not allowed for this category." -- Generates a sortkey for a numeral `n`, adding leading zeroes to avoid the "1, 10, 2, 3" sorting problem. `max_n` is the greatest expected value of `n`, and is used to determine how many leading zeroes are needed. If not supplied, it defaults to the number of languages. function export.numeral_sortkey(n, max_n) max_n = max_n or require("Module:list of languages").count() return ("#%%0%dd"):format(ceil(log10(max_n + 1))):format(n) end function export.split_lang_label(title_text) local getByCanonicalName = require("Module:languages").getByCanonicalName -- Progressively remove a word from the potential canonical name until it -- matches an actual canonical name. --local words = split(title_text, " ", true) --for i = #words - 1, 1, -1 do -- local lang = getByCanonicalName(concat(words, " ", 1, i)) -- if lang then -- return lang, concat(words, " ", i + 1) -- end --end local label, langname = title_text:match("^(.-) بە (.+)$") local lang = getByCanonicalName(langname) if lang then return lang, label end return nil, title_text end local function show_error(text) return require("Module:message box").maintenance( "red", "[[File:Ambox warning pn.svg|50px]]", "ئەم پۆلە لە داری پۆلی ویکیفەرھەنگدا پێناسە نەکراوە.", text ) end -- Show the text that goes at the very top right of the page. local function show_topright(current) return current.getTopright and current:getTopright() or nil end local function link_box(content) return ("<div class=\"noprint plainlinks\" style=\"float: left; clear: both; margin: 0 1em .5em 0; background: var(--wikt-palette-paleblue, #f9f9f9); border: 1px var(--border-color-base, #aaaaaa) solid; margin-top: -1px; padding: 5px; font-weight: bold;\">%s</div>"):format(content) end local function show_editlink(current) return link_box(("[%s دراوەی پۆل دەستکاری بکە]"):format(tostring(full_url(current:getDataModule(), "action=edit")))) end function show_related_changes() local title = current_title.fullText return link_box(("[%s <span title=\"دوایین دەستکاری و گۆڕانکارییەکانی تری پەڕەکانی نێو «%s»\">دوایین گۆڕانکارییەکان</span>]"):format( tostring(full_url("Special:RecentChangesLinked", { target = title, showlinkedto = 0, })), title )) end local function show_pagelist(current) local namespace = "namespace=" local info = current:getInfo() local lang_code = info.code if info.label == "citations" or info.label == "citations of undefined terms" then namespace = namespace .. "Citations" elseif lang_code then local lang = require("Module:languages").getByCode(lang_code, true) if lang then -- Proto-Norse (gmq-pro) is the probably language with a code ending in -pro -- that's intended to have mostly non-reconstructed entries. if (lang_code:find("%-pro$") and lang_code ~= "gmq-pro") or lang:hasType("reconstructed") then namespace = namespace .. "Reconstruction" elseif lang:hasType("appendix-constructed") then namespace = namespace .. "Appendix" end end elseif info.label:match("templates") then namespace = namespace .. "داڕێژە" elseif info.label:match("modules") then namespace = namespace .. "مۆدیوول" elseif info.label:match("^Wiktionary") or info.label:match("^Pages") then namespace = "" end return ([=[ {| id="newest-and-oldest-pages" class="wikitable mw-collapsible mw-collapsed" style="float: left; clear: both; margin: 0 1em .5em 0;" ! نوێترین و کۆنترین پەڕەکان&nbsp; |- | id="recent-additions" style="font-size:0.9em;" | '''نوێترین پەڕەکان بەپێی کۆتا [[mw:Manual:Categorylinks table#cl_timestamp|نوێکردنەوەی بەستەری پۆلەکە]] ڕیز کراون:''' %s |- | id="oldest-pages" style="font-size:0.9em;" | '''کۆنترین پەڕەکان بەپێی کۆتا دەستکاری ڕیز کراون:''' %s |}]=]):format( current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=categoryadd order=descending]=] ):format(current_title.text, namespace) ), current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=lastedit order=ascending]=] ):format(current_title.text, namespace) ) ) end -- Show navigational "breadcrumbs" at the top of the page. local function show_breadcrumbs(current) local steps = {} -- Start at the current label and move our way up the "chain" from child to parent, until we can't go further. while current do local category, display_name, nocap if type(current) == "string" then category = current display_name = current:gsub("^پۆل:", "") else if not current.getCategoryName then error("Internal error: Bad format in breadcrumb chain structure, probably a misformatted value for `parents`: " .. mw.dumpObject(current)) end category = "پۆل:" .. current:getCategoryName() display_name, nocap = current:getBreadcrumbName() end if not nocap then display_name = mw.getContentLanguage():ucfirst(display_name) end insert(steps, 1, ("[[:%s|%s]]"):format(category, display_name)) -- Move up the "chain" by one level. if type(current) == "string" then current = nil else current = current:getParents() end if current then current = current[1].name end end local templateStyles = require("Module:TemplateStyles")(category_tree_styles_css) local ol = mw.html.create("ol") for i, step in ipairs(steps) do local li = mw.html.create("li") if i ~= 1 then local span = mw.html.create("span") :attr("aria-hidden", "true") :addClass("ts-categoryBreadcrumbs-separator") :wikitext(" » ") li:node(span) end li:wikitext(step) ol:node(li) end return templateStyles .. tostring(mw.html.create("div") :attr("role", "navigation") :attr("aria-label", "Breadcrumb") :addClass("ts-categoryBreadcrumbs") :node(ol)) end local function show_also(current) local also = current._info.also if also and #also > 0 then return ('<div style="margin-top:-1em;margin-bottom:1.5em">%s</div>'):format(require("Module:also").main(also)) end return nil end -- Show a short description text for the category. local function show_description(current) return current.getDescription and current:getDescription() or nil end local function show_appendix(current) local appendix = current.getAppendix and current:getAppendix() return appendix and ("For more information, see [[%s]]."):format(appendix) or nil end local function sort_children(child1, child2) return string_compare(uupper(child1.sort), uupper(child2.sort)) end -- Show a list of child categories. local function show_children(current) local children = current.getChildren and current:getChildren() or nil if not children then return nil end sort(children, sort_children) local children_list = {} for _, child in ipairs(children) do local child_name, child_pagetitle = child.name if type(child_name) == "string" then child_pagetitle = child_name else child_pagetitle = "پۆل:" .. child_name:getCategoryName() end if new_title(child_pagetitle).exists then insert(children_list, ("* [[:%s]]: %s"):format( child_pagetitle, child.description or type(child_name) == "string" and child_name:gsub("^پۆل:", "") .. "." or child_name:getDescription("child") )) end end return concat(children_list, "\n") end -- Show a table of contents with links to each letter in the language's script. local function show_TOC(current) local titleText = current_title.text local inCategoryPages = pages_in_category(titleText, "pages") local inCategorySubcats = pages_in_category(titleText, "subcats") local TOC_type -- Compute type of table of contents required. if inCategoryPages > 2500 or inCategorySubcats > 2500 then TOC_type = "full" elseif inCategoryPages > 200 or inCategorySubcats > 200 then TOC_type = "normal" else -- No (usual) need for a TOC if all pages or subcategories can fit on one page; -- but allow this to be overridden by a custom TOC handler. TOC_type = "none" end if current.getTOC then local TOC_text = current:getTOC(TOC_type) if TOC_text ~= true then return TOC_text or nil end end if TOC_type ~= "none" then local templatename = current:getTOCTemplateName() local TOC_template if TOC_type == "full" then -- This category is very large, see if there is a "full" version of the TOC. local TOC_template_full = new_title(templatename .. "/full") if TOC_template_full.exists then TOC_template = TOC_template_full end end if not TOC_template then local TOC_template_normal = new_title(templatename) if TOC_template_normal.exists then TOC_template = TOC_template_normal end end if TOC_template then return current_frame:expandTemplate{title = TOC_template.text, args = {}} end end return nil end -- Show the "catfix" that adds language attributes and script classes to the page. local function show_catfix(current) local lang, sc = current:getCatfixInfo() return lang and m_utilities.catfix(lang, sc) or nil end -- Show the parent categories that the current category should be placed in. local function show_categories(current, categories) local parents = current.getParents and current:getParents() or nil if not parents then return nil end for _, parent in ipairs(parents) do local parent_name = parent.name local sortkey = type(parent.sort) == "table" and parent.sort:makeSortKey() or parent.sort if type(parent_name) == "string" then insert(categories, ("[[%s|%s]]"):format(parent_name, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(parent_name:getCategoryName(), sortkey)) end end -- Also put the category in its corresponding "umbrella" or "by language" category. local umbrella = current:getUmbrella() if umbrella then -- FIXME: use a language-neutral sorting function like the Unicode Collation Algorithm. local sortkey = current._lang and current._lang:getCanonicalName() or current:getCategoryName() sortkey = require("Module:languages").getByCode("en", true):makeSortKey(sortkey) if type(umbrella) == "string" then insert(categories, ("[[%s|%s]]"):format(umbrella, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(umbrella:getCategoryName(), sortkey)) end end -- Check for various unwanted parser functions, which should be integrated into the category tree data instead. -- Note: HTML comments shouldn't be removed from `content` until after this step, as they can affect the result. local content = current_title:getContent() if not content then -- This happens when using [[Special:ExpandTemplates]] to call {{auto cat}} on a nonexistent category page, -- which is needed by Benwing's create_wanted_categories.py script. return end local defaultsort, displaytitle, page_has_param for node in parse(content):iterate_nodes() do local node_class = class_else_type(node) if node_class == "template" then local name = node:get_name() if name == "DEFAULTSORT:" and not defaultsort then insert(categories, "[[پۆل:Pages with DEFAULTSORT conflicts]]") defaultsort = true elseif name == "DISPLAYTITLE:" and not displaytitle then insert(categories,"[[پۆل:Pages with DISPLAYTITLE conflicts]]") displaytitle = true end elseif node_class == "parameter" and not page_has_param then insert(categories,"[[پۆل:Pages with raw triple-brace template parameters]]") page_has_param = true end end -- Check for raw category markup, which should also be integrated into the category tree data. content = remove_comments(content, "BOTH") local head = content:find("[[", 1, true) while head do local close = content:find("]]", head + 2, true) if not close then break end -- Make sure there are no intervening "[[" between head and close. local open = content:find("[[", head + 2, true) while open and open < close do head = open open = content:find("[[", head + 2, true) end local cat = content:sub(head + 2, close - 1) local colon = cat:match("^[ _\128-\244]*[Cc][Aa][Tt][EeGgOoRrYy _\128-\244]*():") if colon then local pipe = cat:find("|", colon + 1, true) if pipe ~= #cat then local title = new_title(pipe and cat:sub(1, pipe - 1) or cat) if title and title.namespace == 14 then insert(categories,"[[پۆل:Categories with categories using raw markup]]") break end end end head = open end end local function generate_output(current) if current then for _, functionName in pairs{ "getBreadcrumbName", "getDataModule", "canBeEmpty", "getDescription", "getParents", "getChildren", "getUmbrella", "getAppendix", "getTOCTemplateName", } do if not is_callable(current[functionName]) then require("Module:debug").track{"category tree/missing function", "category tree/missing function/" .. functionName} end end end local boxes, display, categories = {}, {}, {} -- Categories should never show files as a gallery. insert(categories, "__NOGALLERY__") if current_frame:getParent():getTitle() == "داڕێژە:auto cat" then insert(categories, "[[پۆل:Categories calling Template:auto cat]]") end -- Check if the category is empty local totalPages = pages_in_category(current_title.text, "all") local hugeCategory = totalPages > 1000000 -- 1 million -- Categorize huge categories, as they cause DynamicPageList to time out and make the category inaccessible. if hugeCategory then insert(categories, "[[پۆل:Huge categories]]") end -- Are the parameters valid? if not current then insert(categories, "[[پۆل:ئەو پۆلانەی کە لە داری پۆلەکەدا پێناسە نەکراون]]") insert(categories, totalPages == 0 and "[[پۆل:پۆلە واڵاکان]]" or nil) insert(display, show_error( "Double-check the category name for typos. <br>" .. "[[Special:Search/Category: " .. current_title.text:gsub("^.+:", ""):gsub(" ", "~2 ") .. '~2|Search existing categories]] to check if this category should be created under a different name (for example, "Fruits" instead of "Fruit"). <br>' .. "To add a new category to Wiktionary's category tree, please consult " .. current_frame:expandTemplate{title = "section link", args = { "Help:Category#How_to_create_a_category", }} .. ".")) -- Exit here, as all code beyond here relies on current not being nil return concat(categories, "") .. concat(display, "\n\n"), true end -- Does the category have the correct name? local currentName = current:getCategoryName() local correctName = current_title.text == currentName if not correctName then insert(categories, "[[پۆل:Categories with incorrect names]]") insert(display, show_error(("Based on the data in the category tree, this category should be called '''[[:پۆل:%s]]'''."):format(currentName))) end -- Add cleanup category for empty categories. local canBeEmpty = current:canBeEmpty() if canBeEmpty and correctName then insert(categories, " __EXPECTUNUSEDCATEGORY__") elseif totalPages == 0 then insert(categories, "[[پۆل:پۆلە واڵاکان]]") end if current:isHidden() then insert(categories, "__HIDDENCAT__") end -- Put all the float-right stuff into a <div> that does not clear, so that float-left stuff like the breadcrumbs and -- description can go opposite the float-right stuff without vertical space. insert(boxes, "<div style=\"float: left;\">") insert(boxes, show_topright(current)) insert(boxes, show_editlink(current)) insert(boxes, show_related_changes()) -- Show pagelist, unless it's a huge category (since they can't use DynamicPageList - see above). --if not hugeCategory then -- insert(boxes, show_pagelist(current)) --end insert(boxes, "</div>") -- Generate the displayed information insert(display, show_breadcrumbs(current)) insert(display, show_also(current)) insert(display, show_description(current)) -- insert(display, show_appendix(current)) insert(display, show_children(current)) insert(display, show_TOC(current)) insert(display, show_catfix(current)) insert(display, '<br class="clear-both-in-vector-2022-only">') show_categories(current, categories) return concat(boxes, "\n") .. "\n" .. concat(display, "\n\n") .. concat(categories, "") end --[==[ List of handler functions that try to match the page name. A handler should return the name of a submodule to [[Module:category tree]] and an info table which is passed as an argument to the submodule. If a handler does not recognize the page name, it should return nil. Note that the order of handlers matters! ]==] local handlers = {} -- Thesaurus per-language category insert(handlers, function(title) local code, label = title:match("^Thesaurus:(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Topic per-language category insert(handlers, function(title) local code, label = title:match("^(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Lect category e.g. for [[:Category:New Zealand English]] or [[:Category:Issime Walser]] insert(handlers, function(title, args) local lect = args.lect or args.dialect if lect ~= "" and yesno(lect, true) then -- Same as boolean in [[Module:parameters]]. return poscatboiler_subsystem, {label = title, args = args, raw = true} end end) -- poscatboiler per-language label, e.g. [[Category:English non-lemma forms]] insert(handlers, function(title, args) local lang, label = export.split_lang_label(title) if not lang then return end local baseLabel, script = label:match("(.+) in (.-) script$") if script and baseLabel ~= "terms" then local scriptObj = require("Module:scripts").getByCanonicalName(script) if scriptObj then return poscatboiler_subsystem, {label = baseLabel, code = lang:getCode(), sc = scriptObj:getCode(), args = args} end end return poscatboiler_subsystem, {label = label, code = lang:getCode(), args = args} end) -- poscatboiler label umbrella category insert(handlers, function(title, args) local label = title:match("بەپێی زمان (.+)") if label then -- The poscatboiler code will appropriately lowercase if needed. return poscatboiler_subsystem, {label = label, args = args} end end) -- poscatboiler raw handlers insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args, raw = true} end) -- poscatboiler umbrella handlers without 'by language' insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args} end) function export.show(frame) local args, other_args = require("Module:parameters").process(frame:getParent().args, { ["also"] = {type = "title", sublist = "comma without whitespace", namespace = 14} }, true) if args.also then for k, arg in next, args.also do args.also[k] = arg.prefixedText end end for k, arg in next, other_args do other_args[k] = trim(arg) end if namespace == 10 then -- Template return "(ئەم داڕێژە پێویستە لەسەر پەڕەکانی بۆشاییناوی [[:en:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.)" elseif namespace ~= 14 then -- Category error("ئەم داڕێژە/مۆدیوولە دەکرێ تەنیا لەسەر پەڕەکانی بۆشاییناوی [[mw:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.") end local first_fail_args_handled, first_fail_cattext -- Go through each handler in turn. If a handler doesn't recognize the format of the category, it will return nil, -- and we will consider the next handler. Otherwise, it returns a template name and arguments to call it with, but -- even then, that template might return an error, and we need to consider the next handler. This happens, for -- example, with the category "CAT:Mato Grosso, Brazil", where "Mato" is the name of a language, so the poscatboiler -- per-language label handler fires and tries to find a label "Grosso, Brazil". This throws an error, and -- previously, this blocked fruther handler consideration, but now we check for the error and continue checking -- handlers; eventually, the topic umbrella handler will fire and correctly handle the category. for _, handler in ipairs(handlers) do -- Use a new title object and args table for each handler, to keep them isolated. local submodule, info = handler(current_title.text, deep_copy(other_args)) if submodule then info.also = deep_copy(args.also) require("Module:debug").track("auto cat/" .. submodule) -- `failed` is true if no match was found. submodule = require(category_tree_submodule_prefix .. submodule) local cattext, failed = generate_output(submodule.main(info)) if failed then if not first_fail_cattext then first_fail_cattext = cattext first_fail_args_handled = info.args and true or false end elseif not info.args and next(other_args) then error(extra_args_error) else return cattext end end end -- If there were no matches, throw an error if any arguments were given, or otherwise return the cattext -- from the first fail encountered. The final handlers call the boilers unconditionally, so there should -- always be something to return. if not first_fail_args_handled and next(other_args) then error(extra_args_error) end return first_fail_cattext end -- TODO: new test entrypoint. return export es82p4d0pgo52y2mxchm1pip14v6qga 36940 36931 2026-08-18T01:26:31Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36931|36931]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36940 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local category_tree_submodule_prefix = "Module:category tree/" local category_tree_styles_css = "Module:category tree/styles.css" local m_str_utils = require("Module:string utilities") local m_template_parser = require("Module:template parser") local m_utilities = require("Module:utilities") local ceil = math.ceil local class_else_type = m_template_parser.class_else_type local concat = table.concat local deep_copy = require("Module:table").deepCopy local full_url = mw.uri.fullUrl local insert = table.insert local is_callable = require("Module:fun").is_callable local log10 = math.log10 or require("Module:math").log10 local new_title = mw.title.new local pages_in_category = mw.site.stats.pagesInCategory local parse = m_template_parser.parse local remove_comments = require("Module:string/removeComments") local sort = table.sort local split = m_str_utils.split local string_compare = require("Module:string/compare") local trim = m_str_utils.trim local uupper = m_str_utils.upper local yesno = require("Module:yesno") local current_frame = mw.getCurrentFrame() local current_title = mw.title.getCurrentTitle() local namespace = current_title.namespace local poscatboiler_subsystem = "poscatboiler" local extra_args_error = "Extra arguments to {{((}}auto cat{{))}} are not allowed for this category." -- Generates a sortkey for a numeral `n`, adding leading zeroes to avoid the "1, 10, 2, 3" sorting problem. `max_n` is the greatest expected value of `n`, and is used to determine how many leading zeroes are needed. If not supplied, it defaults to the number of languages. function export.numeral_sortkey(n, max_n) max_n = max_n or require("Module:list of languages").count() return ("#%%0%dd"):format(ceil(log10(max_n + 1))):format(n) end function export.split_lang_label(title_text) local getByCanonicalName = require("Module:languages").getByCanonicalName -- Progressively remove a word from the potential canonical name until it -- matches an actual canonical name. --local words = split(title_text, " ", true) --for i = #words - 1, 1, -1 do -- local lang = getByCanonicalName(concat(words, " ", 1, i)) -- if lang then -- return lang, concat(words, " ", i + 1) -- end --end local label, langname = title_text:match("^(.-) بە (.+)$") local lang = getByCanonicalName(langname) if lang then return lang, label end return nil, title_text end local function show_error(text) return require("Module:message box").maintenance( "red", "[[File:Ambox warning pn.svg|50px]]", "ئەم پۆلە لە داری پۆلی ویکیفەرھەنگدا پێناسە نەکراوە.", text ) end -- Show the text that goes at the very top right of the page. local function show_topright(current) return current.getTopright and current:getTopright() or nil end local function link_box(content) return ("<div class=\"noprint plainlinks\" style=\"float: left; clear: both; margin: 0 1em .5em 0; background: var(--wikt-palette-paleblue, #f9f9f9); border: 1px var(--border-color-base, #aaaaaa) solid; margin-top: -1px; padding: 5px; font-weight: bold;\">%s</div>"):format(content) end local function show_editlink(current) return link_box(("[%s دراوەی پۆل دەستکاری بکە]"):format(tostring(full_url(current:getDataModule(), "action=edit")))) end function show_related_changes() local title = current_title.fullText return link_box(("[%s <span title=\"دوایین دەستکاری و گۆڕانکارییەکانی تری پەڕەکانی نێو «%s»\">دوایین گۆڕانکارییەکان</span>]"):format( tostring(full_url("Special:RecentChangesLinked", { target = title, showlinkedto = 0, })), title )) end local function show_pagelist(current) local namespace = "namespace=" local info = current:getInfo() local lang_code = info.code if info.label == "citations" or info.label == "citations of undefined terms" then namespace = namespace .. "Citations" elseif lang_code then local lang = require("Module:languages").getByCode(lang_code, true) if lang then -- Proto-Norse (gmq-pro) is the probably language with a code ending in -pro -- that's intended to have mostly non-reconstructed entries. if (lang_code:find("%-pro$") and lang_code ~= "gmq-pro") or lang:hasType("reconstructed") then namespace = namespace .. "Reconstruction" elseif lang:hasType("appendix-constructed") then namespace = namespace .. "Appendix" end end elseif info.label:match("templates") then namespace = namespace .. "داڕێژە" elseif info.label:match("modules") then namespace = namespace .. "مۆدیوول" elseif info.label:match("^Wiktionary") or info.label:match("^Pages") then namespace = "" end return ([=[ {| id="newest-and-oldest-pages" class="wikitable mw-collapsible mw-collapsed" style="float: left; clear: both; margin: 0 1em .5em 0;" ! نوێترین و کۆنترین پەڕەکان&nbsp; |- | id="recent-additions" style="font-size:0.9em;" | '''نوێترین پەڕەکان بەپێی کۆتا [[mw:Manual:Categorylinks table#cl_timestamp|نوێکردنەوەی بەستەری پۆلەکە]] ڕیز کراون:''' %s |- | id="oldest-pages" style="font-size:0.9em;" | '''کۆنترین پەڕەکان بەپێی کۆتا دەستکاری ڕیز کراون:''' %s |}]=]):format( current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=categoryadd order=descending]=] ):format(current_title.text, namespace) ), current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=lastedit order=ascending]=] ):format(current_title.text, namespace) ) ) end -- Show navigational "breadcrumbs" at the top of the page. local function show_breadcrumbs(current) local steps = {} -- Start at the current label and move our way up the "chain" from child to parent, until we can't go further. while current do local category, display_name, nocap if type(current) == "string" then category = current display_name = current:gsub("^پۆل:", "") else if not current.getCategoryName then error("Internal error: Bad format in breadcrumb chain structure, probably a misformatted value for `parents`: " .. mw.dumpObject(current)) end category = "پۆل:" .. current:getCategoryName() display_name, nocap = current:getBreadcrumbName() end if not nocap then display_name = mw.getContentLanguage():ucfirst(display_name) end insert(steps, 1, ("[[:%s|%s]]"):format(category, display_name)) -- Move up the "chain" by one level. if type(current) == "string" then current = nil else current = current:getParents() end if current then current = current[1].name end end local templateStyles = require("Module:TemplateStyles")(category_tree_styles_css) local ol = mw.html.create("ol") for i, step in ipairs(steps) do local li = mw.html.create("li") if i ~= 1 then local span = mw.html.create("span") :attr("aria-hidden", "true") :addClass("ts-categoryBreadcrumbs-separator") :wikitext(" » ") li:node(span) end li:wikitext(step) ol:node(li) end return templateStyles .. tostring(mw.html.create("div") :attr("role", "navigation") :attr("aria-label", "Breadcrumb") :addClass("ts-categoryBreadcrumbs") :node(ol)) end local function show_also(current) local also = current._info.also if also and #also > 0 then return ('<div style="margin-top:-1em;margin-bottom:1.5em">%s</div>'):format(require("Module:also").main(also)) end return nil end -- Show a short description text for the category. local function show_description(current) return current.getDescription and current:getDescription() or nil end local function show_appendix(current) local appendix = current.getAppendix and current:getAppendix() return appendix and ("For more information, see [[%s]]."):format(appendix) or nil end local function sort_children(child1, child2) return string_compare(uupper(child1.sort), uupper(child2.sort)) end -- Show a list of child categories. local function show_children(current) local children = current.getChildren and current:getChildren() or nil if not children then return nil end sort(children, sort_children) local children_list = {} for _, child in ipairs(children) do local child_name, child_pagetitle = child.name if type(child_name) == "string" then child_pagetitle = child_name else child_pagetitle = "پۆل:" .. child_name:getCategoryName() end if new_title(child_pagetitle).exists then insert(children_list, ("* [[:%s]]: %s"):format( child_pagetitle, child.description or type(child_name) == "string" and child_name:gsub("^پۆل:", "") .. "." or child_name:getDescription("child") )) end end return concat(children_list, "\n") end -- Show a table of contents with links to each letter in the language's script. local function show_TOC(current) local titleText = current_title.text local inCategoryPages = pages_in_category(titleText, "pages") local inCategorySubcats = pages_in_category(titleText, "subcats") local TOC_type -- Compute type of table of contents required. if inCategoryPages > 2500 or inCategorySubcats > 2500 then TOC_type = "full" elseif inCategoryPages > 200 or inCategorySubcats > 200 then TOC_type = "normal" else -- No (usual) need for a TOC if all pages or subcategories can fit on one page; -- but allow this to be overridden by a custom TOC handler. TOC_type = "none" end if current.getTOC then local TOC_text = current:getTOC(TOC_type) if TOC_text ~= true then return TOC_text or nil end end if TOC_type ~= "none" then local templatename = current:getTOCTemplateName() local TOC_template if TOC_type == "full" then -- This category is very large, see if there is a "full" version of the TOC. local TOC_template_full = new_title(templatename .. "/full") if TOC_template_full.exists then TOC_template = TOC_template_full end end if not TOC_template then local TOC_template_normal = new_title(templatename) if TOC_template_normal.exists then TOC_template = TOC_template_normal end end if TOC_template then return current_frame:expandTemplate{title = TOC_template.text, args = {}} end end return nil end -- Show the "catfix" that adds language attributes and script classes to the page. local function show_catfix(current) local lang, sc = current:getCatfixInfo() return lang and m_utilities.catfix(lang, sc) or nil end -- Show the parent categories that the current category should be placed in. local function show_categories(current, categories) local parents = current.getParents and current:getParents() or nil if not parents then return nil end for _, parent in ipairs(parents) do local parent_name = parent.name local sortkey = type(parent.sort) == "table" and parent.sort:makeSortKey() or parent.sort if type(parent_name) == "string" then insert(categories, ("[[%s|%s]]"):format(parent_name, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(parent_name:getCategoryName(), sortkey)) end end -- Also put the category in its corresponding "umbrella" or "by language" category. local umbrella = current:getUmbrella() if umbrella then -- FIXME: use a language-neutral sorting function like the Unicode Collation Algorithm. local sortkey = current._lang and current._lang:getCanonicalName() or current:getCategoryName() sortkey = require("Module:languages").getByCode("en", true):makeSortKey(sortkey) if type(umbrella) == "string" then insert(categories, ("[[%s|%s]]"):format(umbrella, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(umbrella:getCategoryName(), sortkey)) end end -- Check for various unwanted parser functions, which should be integrated into the category tree data instead. -- Note: HTML comments shouldn't be removed from `content` until after this step, as they can affect the result. local content = current_title:getContent() if not content then -- This happens when using [[Special:ExpandTemplates]] to call {{auto cat}} on a nonexistent category page, -- which is needed by Benwing's create_wanted_categories.py script. return end local defaultsort, displaytitle, page_has_param for node in parse(content):iterate_nodes() do local node_class = class_else_type(node) if node_class == "template" then local name = node:get_name() if name == "DEFAULTSORT:" and not defaultsort then insert(categories, "[[پۆل:Pages with DEFAULTSORT conflicts]]") defaultsort = true elseif name == "DISPLAYTITLE:" and not displaytitle then insert(categories,"[[پۆل:Pages with DISPLAYTITLE conflicts]]") displaytitle = true end elseif node_class == "parameter" and not page_has_param then insert(categories,"[[پۆل:Pages with raw triple-brace template parameters]]") page_has_param = true end end -- Check for raw category markup, which should also be integrated into the category tree data. content = remove_comments(content, "BOTH") local head = content:find("[[", 1, true) while head do local close = content:find("]]", head + 2, true) if not close then break end -- Make sure there are no intervening "[[" between head and close. local open = content:find("[[", head + 2, true) while open and open < close do head = open open = content:find("[[", head + 2, true) end local cat = content:sub(head + 2, close - 1) local colon = cat:match("^[ _\128-\244]*[Cc][Aa][Tt][EeGgOoRrYy _\128-\244]*():") if colon then local pipe = cat:find("|", colon + 1, true) if pipe ~= #cat then local title = new_title(pipe and cat:sub(1, pipe - 1) or cat) if title and title.namespace == 14 then insert(categories,"[[پۆل:Categories with categories using raw markup]]") break end end end head = open end end local function generate_output(current) if current then for _, functionName in pairs{ "getBreadcrumbName", "getDataModule", "canBeEmpty", "getDescription", "getParents", "getChildren", "getUmbrella", "getAppendix", "getTOCTemplateName", } do if not is_callable(current[functionName]) then require("Module:debug").track{"category tree/missing function", "category tree/missing function/" .. functionName} end end end local boxes, display, categories = {}, {}, {} -- Categories should never show files as a gallery. insert(categories, "__NOGALLERY__") if current_frame:getParent():getTitle() == "داڕێژە:auto cat" then insert(categories, "[[پۆل:Categories calling Template:auto cat]]") end -- Check if the category is empty local totalPages = pages_in_category(current_title.text, "all") local hugeCategory = totalPages > 1000000 -- 1 million -- Categorize huge categories, as they cause DynamicPageList to time out and make the category inaccessible. if hugeCategory then insert(categories, "[[پۆل:Huge categories]]") end -- Are the parameters valid? if not current then insert(categories, "[[پۆل:ئەو پۆلانەی کە لە داری پۆلەکەدا پێناسە نەکراون]]") insert(categories, totalPages == 0 and "[[پۆل:پۆلە واڵاکان]]" or nil) insert(display, show_error( "Double-check the category name for typos. <br>" .. "[[Special:Search/Category: " .. current_title.text:gsub("^.+:", ""):gsub(" ", "~2 ") .. '~2|Search existing categories]] to check if this category should be created under a different name (for example, "Fruits" instead of "Fruit"). <br>' .. "To add a new category to Wiktionary's category tree, please consult " .. current_frame:expandTemplate{title = "section link", args = { "Help:Category#How_to_create_a_category", }} .. ".")) -- Exit here, as all code beyond here relies on current not being nil return concat(categories, "") .. concat(display, "\n\n"), true end -- Does the category have the correct name? local currentName = current:getCategoryName() local correctName = current_title.text == currentName if not correctName then insert(categories, "[[پۆل:Categories with incorrect names]]") insert(display, show_error(("Based on the data in the category tree, this category should be called '''[[:پۆل:%s]]'''."):format(currentName))) end -- Add cleanup category for empty categories. local canBeEmpty = current:canBeEmpty() if canBeEmpty and correctName then insert(categories, " __EXPECTUNUSEDCATEGORY__") elseif totalPages == 0 then insert(categories, "[[پۆل:پۆلە واڵاکان]]") end if current:isHidden() then insert(categories, "__HIDDENCAT__") end -- Put all the float-right stuff into a <div> that does not clear, so that float-left stuff like the breadcrumbs and -- description can go opposite the float-right stuff without vertical space. insert(boxes, "<div style=\"float: left;\">") insert(boxes, show_topright(current)) insert(boxes, show_editlink(current)) insert(boxes, show_related_changes()) -- Show pagelist, unless it's a huge category (since they can't use DynamicPageList - see above). --if not hugeCategory then -- insert(boxes, show_pagelist(current)) --end insert(boxes, "</div>") -- Generate the displayed information insert(display, show_breadcrumbs(current)) insert(display, show_also(current)) insert(display, show_description(current)) -- insert(display, show_appendix(current)) insert(display, show_children(current)) insert(display, show_TOC(current)) insert(display, show_catfix(current)) insert(display, '<br class="clear-both-in-vector-2022-only">') show_categories(current, categories) return concat(boxes, "\n") .. "\n" .. concat(display, "\n\n") .. concat(categories, "") end --[==[ List of handler functions that try to match the page name. A handler should return the name of a submodule to [[Module:category tree]] and an info table which is passed as an argument to the submodule. If a handler does not recognize the page name, it should return nil. Note that the order of handlers matters! ]==] local handlers = {} -- Thesaurus per-language category insert(handlers, function(title) local code, label = title:match("^Thesaurus:(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Topic per-language category insert(handlers, function(title) local code, label = title:match("^(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Lect category e.g. for [[:Category:New Zealand English]] or [[:Category:Issime Walser]] insert(handlers, function(title, args) local lect = args.lect or args.dialect if lect ~= "" and yesno(lect, true) then -- Same as boolean in [[Module:parameters]]. return poscatboiler_subsystem, {label = title, args = args, raw = true} end end) -- poscatboiler per-language label, e.g. [[Category:English non-lemma forms]] insert(handlers, function(title, args) local lang, label = export.split_lang_label(title) if not lang then return end local baseLabel, script = label:match("(.+) in (.-) script$") if script and baseLabel ~= "terms" then local scriptObj = require("Module:scripts").getByCanonicalName(script) if scriptObj then return poscatboiler_subsystem, {label = baseLabel, code = lang:getCode(), sc = scriptObj:getCode(), args = args} end end return poscatboiler_subsystem, {label = label, code = lang:getCode(), args = args} end) -- poscatboiler label umbrella category insert(handlers, function(title, args) local label = title:match("(.+) by language$") if label then -- The poscatboiler code will appropriately lowercase if needed. return poscatboiler_subsystem, {label = label, args = args} end end) -- poscatboiler raw handlers insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args, raw = true} end) -- poscatboiler umbrella handlers without 'by language' insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args} end) function export.show(frame) local args, other_args = require("Module:parameters").process(frame:getParent().args, { ["also"] = {type = "title", sublist = "comma without whitespace", namespace = 14} }, true) if args.also then for k, arg in next, args.also do args.also[k] = arg.prefixedText end end for k, arg in next, other_args do other_args[k] = trim(arg) end if namespace == 10 then -- Template return "(ئەم داڕێژە پێویستە لەسەر پەڕەکانی بۆشاییناوی [[:en:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.)" elseif namespace ~= 14 then -- Category error("ئەم داڕێژە/مۆدیوولە دەکرێ تەنیا لەسەر پەڕەکانی بۆشاییناوی [[mw:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.") end local first_fail_args_handled, first_fail_cattext -- Go through each handler in turn. If a handler doesn't recognize the format of the category, it will return nil, -- and we will consider the next handler. Otherwise, it returns a template name and arguments to call it with, but -- even then, that template might return an error, and we need to consider the next handler. This happens, for -- example, with the category "CAT:Mato Grosso, Brazil", where "Mato" is the name of a language, so the poscatboiler -- per-language label handler fires and tries to find a label "Grosso, Brazil". This throws an error, and -- previously, this blocked fruther handler consideration, but now we check for the error and continue checking -- handlers; eventually, the topic umbrella handler will fire and correctly handle the category. for _, handler in ipairs(handlers) do -- Use a new title object and args table for each handler, to keep them isolated. local submodule, info = handler(current_title.text, deep_copy(other_args)) if submodule then info.also = deep_copy(args.also) require("Module:debug").track("auto cat/" .. submodule) -- `failed` is true if no match was found. submodule = require(category_tree_submodule_prefix .. submodule) local cattext, failed = generate_output(submodule.main(info)) if failed then if not first_fail_cattext then first_fail_cattext = cattext first_fail_args_handled = info.args and true or false end elseif not info.args and next(other_args) then error(extra_args_error) else return cattext end end end -- If there were no matches, throw an error if any arguments were given, or otherwise return the cattext -- from the first fail encountered. The final handlers call the boilers unconditionally, so there should -- always be something to return. if not first_fail_args_handled and next(other_args) then error(extra_args_error) end return first_fail_cattext end -- TODO: new test entrypoint. return export 0lncvn4qup3fuhj4huf9jspmvfh9hj8 36943 36940 2026-08-18T01:31:38Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36940|36940]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36943 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local category_tree_submodule_prefix = "Module:category tree/" local category_tree_styles_css = "Module:category tree/styles.css" local m_str_utils = require("Module:string utilities") local m_template_parser = require("Module:template parser") local m_utilities = require("Module:utilities") local ceil = math.ceil local class_else_type = m_template_parser.class_else_type local concat = table.concat local deep_copy = require("Module:table").deepCopy local full_url = mw.uri.fullUrl local insert = table.insert local is_callable = require("Module:fun").is_callable local log10 = math.log10 or require("Module:math").log10 local new_title = mw.title.new local pages_in_category = mw.site.stats.pagesInCategory local parse = m_template_parser.parse local remove_comments = require("Module:string/removeComments") local sort = table.sort local split = m_str_utils.split local string_compare = require("Module:string/compare") local trim = m_str_utils.trim local uupper = m_str_utils.upper local yesno = require("Module:yesno") local current_frame = mw.getCurrentFrame() local current_title = mw.title.getCurrentTitle() local namespace = current_title.namespace local poscatboiler_subsystem = "poscatboiler" local extra_args_error = "Extra arguments to {{((}}auto cat{{))}} are not allowed for this category." -- Generates a sortkey for a numeral `n`, adding leading zeroes to avoid the "1, 10, 2, 3" sorting problem. `max_n` is the greatest expected value of `n`, and is used to determine how many leading zeroes are needed. If not supplied, it defaults to the number of languages. function export.numeral_sortkey(n, max_n) max_n = max_n or require("Module:list of languages").count() return ("#%%0%dd"):format(ceil(log10(max_n + 1))):format(n) end function export.split_lang_label(title_text) local getByCanonicalName = require("Module:languages").getByCanonicalName -- Progressively remove a word from the potential canonical name until it -- matches an actual canonical name. --local words = split(title_text, " ", true) --for i = #words - 1, 1, -1 do -- local lang = getByCanonicalName(concat(words, " ", 1, i)) -- if lang then -- return lang, concat(words, " ", i + 1) -- end --end local label, langname = title_text:match("^(.-) بە (.+)$") local lang = getByCanonicalName(langname) if lang then return lang, label end return nil, title_text end local function show_error(text) return require("Module:message box").maintenance( "red", "[[File:Ambox warning pn.svg|50px]]", "ئەم پۆلە لە داری پۆلی ویکیفەرھەنگدا پێناسە نەکراوە.", text ) end -- Show the text that goes at the very top right of the page. local function show_topright(current) return current.getTopright and current:getTopright() or nil end local function link_box(content) return ("<div class=\"noprint plainlinks\" style=\"float: left; clear: both; margin: 0 1em .5em 0; background: var(--wikt-palette-paleblue, #f9f9f9); border: 1px var(--border-color-base, #aaaaaa) solid; margin-top: -1px; padding: 5px; font-weight: bold;\">%s</div>"):format(content) end local function show_editlink(current) return link_box(("[%s دراوەی پۆل دەستکاری بکە]"):format(tostring(full_url(current:getDataModule(), "action=edit")))) end function show_related_changes() local title = current_title.fullText return link_box(("[%s <span title=\"دوایین دەستکاری و گۆڕانکارییەکانی تری پەڕەکانی نێو «%s»\">دوایین گۆڕانکارییەکان</span>]"):format( tostring(full_url("Special:RecentChangesLinked", { target = title, showlinkedto = 0, })), title )) end local function show_pagelist(current) local namespace = "namespace=" local info = current:getInfo() local lang_code = info.code if info.label == "citations" or info.label == "citations of undefined terms" then namespace = namespace .. "Citations" elseif lang_code then local lang = require("Module:languages").getByCode(lang_code, true) if lang then -- Proto-Norse (gmq-pro) is the probably language with a code ending in -pro -- that's intended to have mostly non-reconstructed entries. if (lang_code:find("%-pro$") and lang_code ~= "gmq-pro") or lang:hasType("reconstructed") then namespace = namespace .. "Reconstruction" elseif lang:hasType("appendix-constructed") then namespace = namespace .. "Appendix" end end elseif info.label:match("templates") then namespace = namespace .. "داڕێژە" elseif info.label:match("modules") then namespace = namespace .. "مۆدیوول" elseif info.label:match("^Wiktionary") or info.label:match("^Pages") then namespace = "" end return ([=[ {| id="newest-and-oldest-pages" class="wikitable mw-collapsible mw-collapsed" style="float: left; clear: both; margin: 0 1em .5em 0;" ! نوێترین و کۆنترین پەڕەکان&nbsp; |- | id="recent-additions" style="font-size:0.9em;" | '''نوێترین پەڕەکان بەپێی کۆتا [[mw:Manual:Categorylinks table#cl_timestamp|نوێکردنەوەی بەستەری پۆلەکە]] ڕیز کراون:''' %s |- | id="oldest-pages" style="font-size:0.9em;" | '''کۆنترین پەڕەکان بەپێی کۆتا دەستکاری ڕیز کراون:''' %s |}]=]):format( current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=categoryadd order=descending]=] ):format(current_title.text, namespace) ), current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=lastedit order=ascending]=] ):format(current_title.text, namespace) ) ) end -- Show navigational "breadcrumbs" at the top of the page. local function show_breadcrumbs(current) local steps = {} -- Start at the current label and move our way up the "chain" from child to parent, until we can't go further. while current do local category, display_name, nocap if type(current) == "string" then category = current display_name = current:gsub("^پۆل:", "") else if not current.getCategoryName then error("Internal error: Bad format in breadcrumb chain structure, probably a misformatted value for `parents`: " .. mw.dumpObject(current)) end category = "پۆل:" .. current:getCategoryName() display_name, nocap = current:getBreadcrumbName() end if not nocap then display_name = mw.getContentLanguage():ucfirst(display_name) end insert(steps, 1, ("[[:%s|%s]]"):format(category, display_name)) -- Move up the "chain" by one level. if type(current) == "string" then current = nil else current = current:getParents() end if current then current = current[1].name end end local templateStyles = require("Module:TemplateStyles")(category_tree_styles_css) local ol = mw.html.create("ol") for i, step in ipairs(steps) do local li = mw.html.create("li") if i ~= 1 then local span = mw.html.create("span") :attr("aria-hidden", "true") :addClass("ts-categoryBreadcrumbs-separator") :wikitext(" » ") li:node(span) end li:wikitext(step) ol:node(li) end return templateStyles .. tostring(mw.html.create("div") :attr("role", "navigation") :attr("aria-label", "Breadcrumb") :addClass("ts-categoryBreadcrumbs") :node(ol)) end local function show_also(current) local also = current._info.also if also and #also > 0 then return ('<div style="margin-top:-1em;margin-bottom:1.5em">%s</div>'):format(require("Module:also").main(also)) end return nil end -- Show a short description text for the category. local function show_description(current) return current.getDescription and current:getDescription() or nil end local function show_appendix(current) local appendix = current.getAppendix and current:getAppendix() return appendix and ("For more information, see [[%s]]."):format(appendix) or nil end local function sort_children(child1, child2) return string_compare(uupper(child1.sort), uupper(child2.sort)) end -- Show a list of child categories. local function show_children(current) local children = current.getChildren and current:getChildren() or nil if not children then return nil end sort(children, sort_children) local children_list = {} for _, child in ipairs(children) do local child_name, child_pagetitle = child.name if type(child_name) == "string" then child_pagetitle = child_name else child_pagetitle = "پۆل:" .. child_name:getCategoryName() end if new_title(child_pagetitle).exists then insert(children_list, ("* [[:%s]]: %s"):format( child_pagetitle, child.description or type(child_name) == "string" and child_name:gsub("^پۆل:", "") .. "." or child_name:getDescription("child") )) end end return concat(children_list, "\n") end -- Show a table of contents with links to each letter in the language's script. local function show_TOC(current) local titleText = current_title.text local inCategoryPages = pages_in_category(titleText, "pages") local inCategorySubcats = pages_in_category(titleText, "subcats") local TOC_type -- Compute type of table of contents required. if inCategoryPages > 2500 or inCategorySubcats > 2500 then TOC_type = "full" elseif inCategoryPages > 200 or inCategorySubcats > 200 then TOC_type = "normal" else -- No (usual) need for a TOC if all pages or subcategories can fit on one page; -- but allow this to be overridden by a custom TOC handler. TOC_type = "none" end if current.getTOC then local TOC_text = current:getTOC(TOC_type) if TOC_text ~= true then return TOC_text or nil end end if TOC_type ~= "none" then local templatename = current:getTOCTemplateName() local TOC_template if TOC_type == "full" then -- This category is very large, see if there is a "full" version of the TOC. local TOC_template_full = new_title(templatename .. "/full") if TOC_template_full.exists then TOC_template = TOC_template_full end end if not TOC_template then local TOC_template_normal = new_title(templatename) if TOC_template_normal.exists then TOC_template = TOC_template_normal end end if TOC_template then return current_frame:expandTemplate{title = TOC_template.text, args = {}} end end return nil end -- Show the "catfix" that adds language attributes and script classes to the page. local function show_catfix(current) local lang, sc = current:getCatfixInfo() return lang and m_utilities.catfix(lang, sc) or nil end -- Show the parent categories that the current category should be placed in. local function show_categories(current, categories) local parents = current.getParents and current:getParents() or nil if not parents then return nil end for _, parent in ipairs(parents) do local parent_name = parent.name local sortkey = type(parent.sort) == "table" and parent.sort:makeSortKey() or parent.sort if type(parent_name) == "string" then insert(categories, ("[[%s|%s]]"):format(parent_name, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(parent_name:getCategoryName(), sortkey)) end end -- Also put the category in its corresponding "umbrella" or "by language" category. local umbrella = current:getUmbrella() if umbrella then -- FIXME: use a language-neutral sorting function like the Unicode Collation Algorithm. local sortkey = current._lang and current._lang:getCanonicalName() or current:getCategoryName() sortkey = require("Module:languages").getByCode("en", true):makeSortKey(sortkey) if type(umbrella) == "string" then insert(categories, ("[[%s|%s]]"):format(umbrella, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(umbrella:getCategoryName(), sortkey)) end end -- Check for various unwanted parser functions, which should be integrated into the category tree data instead. -- Note: HTML comments shouldn't be removed from `content` until after this step, as they can affect the result. local content = current_title:getContent() if not content then -- This happens when using [[Special:ExpandTemplates]] to call {{auto cat}} on a nonexistent category page, -- which is needed by Benwing's create_wanted_categories.py script. return end local defaultsort, displaytitle, page_has_param for node in parse(content):iterate_nodes() do local node_class = class_else_type(node) if node_class == "template" then local name = node:get_name() if name == "DEFAULTSORT:" and not defaultsort then insert(categories, "[[پۆل:Pages with DEFAULTSORT conflicts]]") defaultsort = true elseif name == "DISPLAYTITLE:" and not displaytitle then insert(categories,"[[پۆل:Pages with DISPLAYTITLE conflicts]]") displaytitle = true end elseif node_class == "parameter" and not page_has_param then insert(categories,"[[پۆل:Pages with raw triple-brace template parameters]]") page_has_param = true end end -- Check for raw category markup, which should also be integrated into the category tree data. content = remove_comments(content, "BOTH") local head = content:find("[[", 1, true) while head do local close = content:find("]]", head + 2, true) if not close then break end -- Make sure there are no intervening "[[" between head and close. local open = content:find("[[", head + 2, true) while open and open < close do head = open open = content:find("[[", head + 2, true) end local cat = content:sub(head + 2, close - 1) local colon = cat:match("^[ _\128-\244]*[Cc][Aa][Tt][EeGgOoRrYy _\128-\244]*():") if colon then local pipe = cat:find("|", colon + 1, true) if pipe ~= #cat then local title = new_title(pipe and cat:sub(1, pipe - 1) or cat) if title and title.namespace == 14 then insert(categories,"[[پۆل:Categories with categories using raw markup]]") break end end end head = open end end local function generate_output(current) if current then for _, functionName in pairs{ "getBreadcrumbName", "getDataModule", "canBeEmpty", "getDescription", "getParents", "getChildren", "getUmbrella", "getAppendix", "getTOCTemplateName", } do if not is_callable(current[functionName]) then require("Module:debug").track{"category tree/missing function", "category tree/missing function/" .. functionName} end end end local boxes, display, categories = {}, {}, {} -- Categories should never show files as a gallery. insert(categories, "__NOGALLERY__") if current_frame:getParent():getTitle() == "داڕێژە:auto cat" then insert(categories, "[[پۆل:Categories calling Template:auto cat]]") end -- Check if the category is empty local totalPages = pages_in_category(current_title.text, "all") local hugeCategory = totalPages > 1000000 -- 1 million -- Categorize huge categories, as they cause DynamicPageList to time out and make the category inaccessible. if hugeCategory then insert(categories, "[[پۆل:Huge categories]]") end -- Are the parameters valid? if not current then insert(categories, "[[پۆل:ئەو پۆلانەی کە لە داری پۆلەکەدا پێناسە نەکراون]]") insert(categories, totalPages == 0 and "[[پۆل:پۆلە واڵاکان]]" or nil) insert(display, show_error( "Double-check the category name for typos. <br>" .. "[[Special:Search/Category: " .. current_title.text:gsub("^.+:", ""):gsub(" ", "~2 ") .. '~2|Search existing categories]] to check if this category should be created under a different name (for example, "Fruits" instead of "Fruit"). <br>' .. "To add a new category to Wiktionary's category tree, please consult " .. current_frame:expandTemplate{title = "section link", args = { "Help:Category#How_to_create_a_category", }} .. ".")) -- Exit here, as all code beyond here relies on current not being nil return concat(categories, "") .. concat(display, "\n\n"), true end -- Does the category have the correct name? local currentName = current:getCategoryName() local correctName = current_title.text == currentName if not correctName then insert(categories, "[[پۆل:Categories with incorrect names]]") insert(display, show_error(("Based on the data in the category tree, this category should be called '''[[:پۆل:%s]]'''."):format(currentName))) end -- Add cleanup category for empty categories. local canBeEmpty = current:canBeEmpty() if canBeEmpty and correctName then insert(categories, " __EXPECTUNUSEDCATEGORY__") elseif totalPages == 0 then insert(categories, "[[پۆل:پۆلە واڵاکان]]") end if current:isHidden() then insert(categories, "__HIDDENCAT__") end -- Put all the float-right stuff into a <div> that does not clear, so that float-left stuff like the breadcrumbs and -- description can go opposite the float-right stuff without vertical space. insert(boxes, "<div style=\"float: left;\">") insert(boxes, show_topright(current)) insert(boxes, show_editlink(current)) insert(boxes, show_related_changes()) -- Show pagelist, unless it's a huge category (since they can't use DynamicPageList - see above). --if not hugeCategory then -- insert(boxes, show_pagelist(current)) --end insert(boxes, "</div>") -- Generate the displayed information insert(display, show_breadcrumbs(current)) insert(display, show_also(current)) insert(display, show_description(current)) -- insert(display, show_appendix(current)) insert(display, show_children(current)) insert(display, show_TOC(current)) insert(display, show_catfix(current)) insert(display, '<br class="clear-both-in-vector-2022-only">') show_categories(current, categories) return concat(boxes, "\n") .. "\n" .. concat(display, "\n\n") .. concat(categories, "") end --[==[ List of handler functions that try to match the page name. A handler should return the name of a submodule to [[Module:category tree]] and an info table which is passed as an argument to the submodule. If a handler does not recognize the page name, it should return nil. Note that the order of handlers matters! ]==] local handlers = {} -- Thesaurus per-language category insert(handlers, function(title) local code, label = title:match("^Thesaurus:(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Topic per-language category insert(handlers, function(title) local code, label = title:match("^(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Lect category e.g. for [[:Category:New Zealand English]] or [[:Category:Issime Walser]] insert(handlers, function(title, args) local lect = args.lect or args.dialect if lect ~= "" and yesno(lect, true) then -- Same as boolean in [[Module:parameters]]. return poscatboiler_subsystem, {label = title, args = args, raw = true} end end) -- poscatboiler per-language label, e.g. [[Category:English non-lemma forms]] insert(handlers, function(title, args) local lang, label = export.split_lang_label(title) if not lang then return end local baseLabel, script = label:match("(.+) in (.-) script$") if script and baseLabel ~= "terms" then local scriptObj = require("Module:scripts").getByCanonicalName(script) if scriptObj then return poscatboiler_subsystem, {label = baseLabel, code = lang:getCode(), sc = scriptObj:getCode(), args = args} end end return poscatboiler_subsystem, {label = label, code = lang:getCode(), args = args} end) -- poscatboiler label umbrella category insert(handlers, function(title, args) local label = title:match("بەپێی زمان (.+)") if label then -- The poscatboiler code will appropriately lowercase if needed. return poscatboiler_subsystem, {label = label, args = args} end end) -- poscatboiler raw handlers insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args, raw = true} end) -- poscatboiler umbrella handlers without 'by language' insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args} end) function export.show(frame) local args, other_args = require("Module:parameters").process(frame:getParent().args, { ["also"] = {type = "title", sublist = "comma without whitespace", namespace = 14} }, true) if args.also then for k, arg in next, args.also do args.also[k] = arg.prefixedText end end for k, arg in next, other_args do other_args[k] = trim(arg) end if namespace == 10 then -- Template return "(ئەم داڕێژە پێویستە لەسەر پەڕەکانی بۆشاییناوی [[:en:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.)" elseif namespace ~= 14 then -- Category error("ئەم داڕێژە/مۆدیوولە دەکرێ تەنیا لەسەر پەڕەکانی بۆشاییناوی [[mw:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.") end local first_fail_args_handled, first_fail_cattext -- Go through each handler in turn. If a handler doesn't recognize the format of the category, it will return nil, -- and we will consider the next handler. Otherwise, it returns a template name and arguments to call it with, but -- even then, that template might return an error, and we need to consider the next handler. This happens, for -- example, with the category "CAT:Mato Grosso, Brazil", where "Mato" is the name of a language, so the poscatboiler -- per-language label handler fires and tries to find a label "Grosso, Brazil". This throws an error, and -- previously, this blocked fruther handler consideration, but now we check for the error and continue checking -- handlers; eventually, the topic umbrella handler will fire and correctly handle the category. for _, handler in ipairs(handlers) do -- Use a new title object and args table for each handler, to keep them isolated. local submodule, info = handler(current_title.text, deep_copy(other_args)) if submodule then info.also = deep_copy(args.also) require("Module:debug").track("auto cat/" .. submodule) -- `failed` is true if no match was found. submodule = require(category_tree_submodule_prefix .. submodule) local cattext, failed = generate_output(submodule.main(info)) if failed then if not first_fail_cattext then first_fail_cattext = cattext first_fail_args_handled = info.args and true or false end elseif not info.args and next(other_args) then error(extra_args_error) else return cattext end end end -- If there were no matches, throw an error if any arguments were given, or otherwise return the cattext -- from the first fail encountered. The final handlers call the boilers unconditionally, so there should -- always be something to return. if not first_fail_args_handled and next(other_args) then error(extra_args_error) end return first_fail_cattext end -- TODO: new test entrypoint. return export es82p4d0pgo52y2mxchm1pip14v6qga 36944 36943 2026-08-18T01:35:27Z Ghybu 12 36944 Scribunto text/plain -- Prevent substitution. if mw.isSubsting() then return require("Module:unsubst") end local export = {} local category_tree_submodule_prefix = "Module:category tree/" local category_tree_styles_css = "Module:category tree/styles.css" local m_str_utils = require("Module:string utilities") local m_template_parser = require("Module:template parser") local m_utilities = require("Module:utilities") local ceil = math.ceil local class_else_type = m_template_parser.class_else_type local concat = table.concat local deep_copy = require("Module:table").deepCopy local full_url = mw.uri.fullUrl local insert = table.insert local is_callable = require("Module:fun").is_callable local log10 = math.log10 or require("Module:math").log10 local new_title = mw.title.new local pages_in_category = mw.site.stats.pagesInCategory local parse = m_template_parser.parse local remove_comments = require("Module:string/removeComments") local sort = table.sort local split = m_str_utils.split local string_compare = require("Module:string/compare") local trim = m_str_utils.trim local uupper = m_str_utils.upper local yesno = require("Module:yesno") local current_frame = mw.getCurrentFrame() local current_title = mw.title.getCurrentTitle() local namespace = current_title.namespace local poscatboiler_subsystem = "poscatboiler" local extra_args_error = "Extra arguments to {{((}}auto cat{{))}} are not allowed for this category." -- Generates a sortkey for a numeral `n`, adding leading zeroes to avoid the "1, 10, 2, 3" sorting problem. `max_n` is the greatest expected value of `n`, and is used to determine how many leading zeroes are needed. If not supplied, it defaults to the number of languages. function export.numeral_sortkey(n, max_n) max_n = max_n or require("Module:list of languages").count() return ("#%%0%dd"):format(ceil(log10(max_n + 1))):format(n) end function export.split_lang_label(title_text) local getByCanonicalName = require("Module:languages").getByCanonicalName -- Progressively remove a word from the potential canonical name until it -- matches an actual canonical name. --local words = split(title_text, " ", true) --for i = #words - 1, 1, -1 do -- local lang = getByCanonicalName(concat(words, " ", 1, i)) -- if lang then -- return lang, concat(words, " ", i + 1) -- end --end local label, langname = title_text:match("^(.-) بە (.+)$") local lang = getByCanonicalName(langname) if lang then return lang, label end return nil, title_text end local function show_error(text) return require("Module:message box").maintenance( "red", "[[File:Ambox warning pn.svg|50px]]", "ئەم پۆلە لە داری پۆلی ویکیفەرھەنگدا پێناسە نەکراوە.", text ) end -- Show the text that goes at the very top right of the page. local function show_topright(current) return current.getTopright and current:getTopright() or nil end local function link_box(content) return ("<div class=\"noprint plainlinks\" style=\"float: left; clear: both; margin: 0 1em .5em 0; background: var(--wikt-palette-paleblue, #f9f9f9); border: 1px var(--border-color-base, #aaaaaa) solid; margin-top: -1px; padding: 5px; font-weight: bold;\">%s</div>"):format(content) end local function show_editlink(current) return link_box(("[%s دراوەی پۆل دەستکاری بکە]"):format(tostring(full_url(current:getDataModule(), "action=edit")))) end function show_related_changes() local title = current_title.fullText return link_box(("[%s <span title=\"دوایین دەستکاری و گۆڕانکارییەکانی تری پەڕەکانی نێو «%s»\">دوایین گۆڕانکارییەکان</span>]"):format( tostring(full_url("Special:RecentChangesLinked", { target = title, showlinkedto = 0, })), title )) end local function show_pagelist(current) local namespace = "namespace=" local info = current:getInfo() local lang_code = info.code if info.label == "citations" or info.label == "citations of undefined terms" then namespace = namespace .. "Citations" elseif lang_code then local lang = require("Module:languages").getByCode(lang_code, true) if lang then -- Proto-Norse (gmq-pro) is the probably language with a code ending in -pro -- that's intended to have mostly non-reconstructed entries. if (lang_code:find("%-pro$") and lang_code ~= "gmq-pro") or lang:hasType("reconstructed") then namespace = namespace .. "Reconstruction" elseif lang:hasType("appendix-constructed") then namespace = namespace .. "Appendix" end end elseif info.label:match("templates") then namespace = namespace .. "داڕێژە" elseif info.label:match("modules") then namespace = namespace .. "مۆدیوول" elseif info.label:match("^Wiktionary") or info.label:match("^Pages") then namespace = "" end return ([=[ {| id="newest-and-oldest-pages" class="wikitable mw-collapsible mw-collapsed" style="float: left; clear: both; margin: 0 1em .5em 0;" ! نوێترین و کۆنترین پەڕەکان&nbsp; |- | id="recent-additions" style="font-size:0.9em;" | '''نوێترین پەڕەکان بەپێی کۆتا [[mw:Manual:Categorylinks table#cl_timestamp|نوێکردنەوەی بەستەری پۆلەکە]] ڕیز کراون:''' %s |- | id="oldest-pages" style="font-size:0.9em;" | '''کۆنترین پەڕەکان بەپێی کۆتا دەستکاری ڕیز کراون:''' %s |}]=]):format( current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=categoryadd order=descending]=] ):format(current_title.text, namespace) ), current_frame:extensionTag( "DynamicPageList", ([=[ category=%s %s count=10 mode=ordered ordermethod=lastedit order=ascending]=] ):format(current_title.text, namespace) ) ) end -- Show navigational "breadcrumbs" at the top of the page. local function show_breadcrumbs(current) local steps = {} -- Start at the current label and move our way up the "chain" from child to parent, until we can't go further. while current do local category, display_name, nocap if type(current) == "string" then category = current display_name = current:gsub("^پۆل:", "") else if not current.getCategoryName then error("Internal error: Bad format in breadcrumb chain structure, probably a misformatted value for `parents`: " .. mw.dumpObject(current)) end category = "پۆل:" .. current:getCategoryName() display_name, nocap = current:getBreadcrumbName() end if not nocap then display_name = mw.getContentLanguage():ucfirst(display_name) end insert(steps, 1, ("[[:%s|%s]]"):format(category, display_name)) -- Move up the "chain" by one level. if type(current) == "string" then current = nil else current = current:getParents() end if current then current = current[1].name end end local templateStyles = require("Module:TemplateStyles")(category_tree_styles_css) local ol = mw.html.create("ol") for i, step in ipairs(steps) do local li = mw.html.create("li") if i ~= 1 then local span = mw.html.create("span") :attr("aria-hidden", "true") :addClass("ts-categoryBreadcrumbs-separator") :wikitext(" » ") li:node(span) end li:wikitext(step) ol:node(li) end return templateStyles .. tostring(mw.html.create("div") :attr("role", "navigation") :attr("aria-label", "Breadcrumb") :addClass("ts-categoryBreadcrumbs") :node(ol)) end local function show_also(current) local also = current._info.also if also and #also > 0 then return ('<div style="margin-top:-1em;margin-bottom:1.5em">%s</div>'):format(require("Module:also").main(also)) end return nil end -- Show a short description text for the category. local function show_description(current) return current.getDescription and current:getDescription() or nil end local function show_appendix(current) local appendix = current.getAppendix and current:getAppendix() return appendix and ("For more information, see [[%s]]."):format(appendix) or nil end local function sort_children(child1, child2) return string_compare(uupper(child1.sort), uupper(child2.sort)) end -- Show a list of child categories. local function show_children(current) local children = current.getChildren and current:getChildren() or nil if not children then return nil end sort(children, sort_children) local children_list = {} for _, child in ipairs(children) do local child_name, child_pagetitle = child.name if type(child_name) == "string" then child_pagetitle = child_name else child_pagetitle = "پۆل:" .. child_name:getCategoryName() end if new_title(child_pagetitle).exists then insert(children_list, ("* [[:%s]]: %s"):format( child_pagetitle, child.description or type(child_name) == "string" and child_name:gsub("^پۆل:", "") .. "." or child_name:getDescription("child") )) end end return concat(children_list, "\n") end -- Show a table of contents with links to each letter in the language's script. local function show_TOC(current) local titleText = current_title.text local inCategoryPages = pages_in_category(titleText, "pages") local inCategorySubcats = pages_in_category(titleText, "subcats") local TOC_type -- Compute type of table of contents required. if inCategoryPages > 2500 or inCategorySubcats > 2500 then TOC_type = "full" elseif inCategoryPages > 200 or inCategorySubcats > 200 then TOC_type = "normal" else -- No (usual) need for a TOC if all pages or subcategories can fit on one page; -- but allow this to be overridden by a custom TOC handler. TOC_type = "none" end if current.getTOC then local TOC_text = current:getTOC(TOC_type) if TOC_text ~= true then return TOC_text or nil end end if TOC_type ~= "none" then local templatename = current:getTOCTemplateName() local TOC_template if TOC_type == "full" then -- This category is very large, see if there is a "full" version of the TOC. local TOC_template_full = new_title(templatename .. "/full") if TOC_template_full.exists then TOC_template = TOC_template_full end end if not TOC_template then local TOC_template_normal = new_title(templatename) if TOC_template_normal.exists then TOC_template = TOC_template_normal end end if TOC_template then return current_frame:expandTemplate{title = TOC_template.text, args = {}} end end return nil end -- Show the "catfix" that adds language attributes and script classes to the page. local function show_catfix(current) local lang, sc = current:getCatfixInfo() return lang and m_utilities.catfix(lang, sc) or nil end -- Show the parent categories that the current category should be placed in. local function show_categories(current, categories) local parents = current.getParents and current:getParents() or nil if not parents then return nil end for _, parent in ipairs(parents) do local parent_name = parent.name local sortkey = type(parent.sort) == "table" and parent.sort:makeSortKey() or parent.sort if type(parent_name) == "string" then insert(categories, ("[[%s|%s]]"):format(parent_name, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(parent_name:getCategoryName(), sortkey)) end end -- Also put the category in its corresponding "umbrella" or "by language" category. local umbrella = current:getUmbrella() if umbrella then -- FIXME: use a language-neutral sorting function like the Unicode Collation Algorithm. local sortkey = current._lang and current._lang:getCanonicalName() or current:getCategoryName() sortkey = require("Module:languages").getByCode("en", true):makeSortKey(sortkey) if type(umbrella) == "string" then insert(categories, ("[[%s|%s]]"):format(umbrella, sortkey)) else insert(categories, ("[[پۆل:%s|%s]]"):format(umbrella:getCategoryName(), sortkey)) end end -- Check for various unwanted parser functions, which should be integrated into the category tree data instead. -- Note: HTML comments shouldn't be removed from `content` until after this step, as they can affect the result. local content = current_title:getContent() if not content then -- This happens when using [[Special:ExpandTemplates]] to call {{auto cat}} on a nonexistent category page, -- which is needed by Benwing's create_wanted_categories.py script. return end local defaultsort, displaytitle, page_has_param for node in parse(content):iterate_nodes() do local node_class = class_else_type(node) if node_class == "template" then local name = node:get_name() if name == "DEFAULTSORT:" and not defaultsort then insert(categories, "[[پۆل:Pages with DEFAULTSORT conflicts]]") defaultsort = true elseif name == "DISPLAYTITLE:" and not displaytitle then insert(categories,"[[پۆل:Pages with DISPLAYTITLE conflicts]]") displaytitle = true end elseif node_class == "parameter" and not page_has_param then insert(categories,"[[پۆل:Pages with raw triple-brace template parameters]]") page_has_param = true end end -- Check for raw category markup, which should also be integrated into the category tree data. content = remove_comments(content, "BOTH") local head = content:find("[[", 1, true) while head do local close = content:find("]]", head + 2, true) if not close then break end -- Make sure there are no intervening "[[" between head and close. local open = content:find("[[", head + 2, true) while open and open < close do head = open open = content:find("[[", head + 2, true) end local cat = content:sub(head + 2, close - 1) local colon = cat:match("^[ _\128-\244]*[Cc][Aa][Tt][EeGgOoRrYy _\128-\244]*():") if colon then local pipe = cat:find("|", colon + 1, true) if pipe ~= #cat then local title = new_title(pipe and cat:sub(1, pipe - 1) or cat) if title and title.namespace == 14 then insert(categories,"[[پۆل:Categories with categories using raw markup]]") break end end end head = open end end local function generate_output(current) if current then for _, functionName in pairs{ "getBreadcrumbName", "getDataModule", "canBeEmpty", "getDescription", "getParents", "getChildren", "getUmbrella", "getAppendix", "getTOCTemplateName", } do if not is_callable(current[functionName]) then require("Module:debug").track{"category tree/missing function", "category tree/missing function/" .. functionName} end end end local boxes, display, categories = {}, {}, {} -- Categories should never show files as a gallery. insert(categories, "__NOGALLERY__") if current_frame:getParent():getTitle() == "داڕێژە:auto cat" then insert(categories, "[[پۆل:Categories calling Template:auto cat]]") end -- Check if the category is empty local totalPages = pages_in_category(current_title.text, "all") local hugeCategory = totalPages > 1000000 -- 1 million -- Categorize huge categories, as they cause DynamicPageList to time out and make the category inaccessible. if hugeCategory then insert(categories, "[[پۆل:Huge categories]]") end -- Are the parameters valid? if not current then insert(categories, "[[پۆل:ئەو پۆلانەی کە لە داری پۆلەکەدا پێناسە نەکراون]]") insert(categories, totalPages == 0 and "[[پۆل:پۆلە واڵاکان]]" or nil) insert(display, show_error( "Double-check the category name for typos. <br>" .. "[[Special:Search/Category: " .. current_title.text:gsub("^.+:", ""):gsub(" ", "~2 ") .. '~2|Search existing categories]] to check if this category should be created under a different name (for example, "Fruits" instead of "Fruit"). <br>' .. "To add a new category to Wiktionary's category tree, please consult " .. current_frame:expandTemplate{title = "section link", args = { "Help:Category#How_to_create_a_category", }} .. ".")) -- Exit here, as all code beyond here relies on current not being nil return concat(categories, "") .. concat(display, "\n\n"), true end -- Does the category have the correct name? local currentName = current:getCategoryName() local correctName = current_title.text == currentName if not correctName then insert(categories, "[[پۆل:Categories with incorrect names]]") insert(display, show_error(("Based on the data in the category tree, this category should be called '''[[:پۆل:%s]]'''."):format(currentName))) end -- Add cleanup category for empty categories. local canBeEmpty = current:canBeEmpty() if canBeEmpty and correctName then insert(categories, " __EXPECTUNUSEDCATEGORY__") elseif totalPages == 0 then insert(categories, "[[پۆل:پۆلە واڵاکان]]") end if current:isHidden() then insert(categories, "__HIDDENCAT__") end -- Put all the float-right stuff into a <div> that does not clear, so that float-left stuff like the breadcrumbs and -- description can go opposite the float-right stuff without vertical space. insert(boxes, "<div style=\"float: left;\">") insert(boxes, show_topright(current)) insert(boxes, show_editlink(current)) insert(boxes, show_related_changes()) -- Show pagelist, unless it's a huge category (since they can't use DynamicPageList - see above). --if not hugeCategory then -- insert(boxes, show_pagelist(current)) --end insert(boxes, "</div>") -- Generate the displayed information insert(display, show_breadcrumbs(current)) insert(display, show_also(current)) insert(display, show_description(current)) -- insert(display, show_appendix(current)) insert(display, show_children(current)) insert(display, show_TOC(current)) insert(display, show_catfix(current)) insert(display, '<br class="clear-both-in-vector-2022-only">') show_categories(current, categories) return concat(boxes, "\n") .. "\n" .. concat(display, "\n\n") .. concat(categories, "") end --[==[ List of handler functions that try to match the page name. A handler should return the name of a submodule to [[Module:category tree]] and an info table which is passed as an argument to the submodule. If a handler does not recognize the page name, it should return nil. Note that the order of handlers matters! ]==] local handlers = {} -- Thesaurus per-language category insert(handlers, function(title) local code, label = title:match("^Thesaurus:(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Topic per-language category insert(handlers, function(title) local code, label = title:match("^(%l[%a-]*%a):(.+)") if code then return poscatboiler_subsystem, {label = title, raw = true} end end) -- Lect category e.g. for [[:Category:New Zealand English]] or [[:Category:Issime Walser]] insert(handlers, function(title, args) local lect = args.lect or args.dialect if lect ~= "" and yesno(lect, true) then -- Same as boolean in [[Module:parameters]]. return poscatboiler_subsystem, {label = title, args = args, raw = true} end end) -- poscatboiler per-language label, e.g. [[Category:English non-lemma forms]] insert(handlers, function(title, args) local lang, label = export.split_lang_label(title) if not lang then return end local baseLabel, script = label:match("(.+) in (.-) script$") if script and baseLabel ~= "terms" then local scriptObj = require("Module:scripts").getByCanonicalName(script) if scriptObj then return poscatboiler_subsystem, {label = baseLabel, code = lang:getCode(), sc = scriptObj:getCode(), args = args} end end return poscatboiler_subsystem, {label = label, code = lang:getCode(), args = args} end) -- poscatboiler label umbrella category insert(handlers, function(title, args) local label = title:match("(.+) بەپێی زمان") if label then -- The poscatboiler code will appropriately lowercase if needed. return poscatboiler_subsystem, {label = label, args = args} end end) -- poscatboiler raw handlers insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args, raw = true} end) -- poscatboiler umbrella handlers without 'by language' insert(handlers, function(title, args) return poscatboiler_subsystem, {label = title, args = args} end) function export.show(frame) local args, other_args = require("Module:parameters").process(frame:getParent().args, { ["also"] = {type = "title", sublist = "comma without whitespace", namespace = 14} }, true) if args.also then for k, arg in next, args.also do args.also[k] = arg.prefixedText end end for k, arg in next, other_args do other_args[k] = trim(arg) end if namespace == 10 then -- Template return "(ئەم داڕێژە پێویستە لەسەر پەڕەکانی بۆشاییناوی [[:en:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.)" elseif namespace ~= 14 then -- Category error("ئەم داڕێژە/مۆدیوولە دەکرێ تەنیا لەسەر پەڕەکانی بۆشاییناوی [[mw:Help:Namespaces#Category|پۆل:]] بەکاربھێنرێت.") end local first_fail_args_handled, first_fail_cattext -- Go through each handler in turn. If a handler doesn't recognize the format of the category, it will return nil, -- and we will consider the next handler. Otherwise, it returns a template name and arguments to call it with, but -- even then, that template might return an error, and we need to consider the next handler. This happens, for -- example, with the category "CAT:Mato Grosso, Brazil", where "Mato" is the name of a language, so the poscatboiler -- per-language label handler fires and tries to find a label "Grosso, Brazil". This throws an error, and -- previously, this blocked fruther handler consideration, but now we check for the error and continue checking -- handlers; eventually, the topic umbrella handler will fire and correctly handle the category. for _, handler in ipairs(handlers) do -- Use a new title object and args table for each handler, to keep them isolated. local submodule, info = handler(current_title.text, deep_copy(other_args)) if submodule then info.also = deep_copy(args.also) require("Module:debug").track("auto cat/" .. submodule) -- `failed` is true if no match was found. submodule = require(category_tree_submodule_prefix .. submodule) local cattext, failed = generate_output(submodule.main(info)) if failed then if not first_fail_cattext then first_fail_cattext = cattext first_fail_args_handled = info.args and true or false end elseif not info.args and next(other_args) then error(extra_args_error) else return cattext end end end -- If there were no matches, throw an error if any arguments were given, or otherwise return the cattext -- from the first fail encountered. The final handlers call the boilers unconditionally, so there should -- always be something to return. if not first_fail_args_handled and next(other_args) then error(extra_args_error) end return first_fail_cattext end -- TODO: new test entrypoint. return export 2papq0onifznmty3rc0nf5vulhsq67d مۆدیوول:category tree/poscatboiler 828 21 36933 36744 2026-08-18T00:29:54Z Ghybu 12 بەپێی زمان (by language) 36933 Scribunto text/plain local lang_independent_data = require("Module:category tree/data") local lang_specific_module = "Module:category tree/lang" local lang_specific_module_prefix = lang_specific_module .. "/" local family_specific_module = "Module:category tree/fam" local family_specific_module_prefix = family_specific_module .. "/" local labels_utilities_module = "Module:labels/utilities" local template_parser_module = "Module:template parser" local concat = table.concat local dump = mw.dumpObject local expand_template = require("Module:frame").expandTemplate local insert = table.insert local is_callable = require("Module:fun").is_callable local lcfirst = require("Module:string utilities").lcfirst local list_to_set = require("Module:table").listToSet local make_title = mw.title.makeTitle local new_title = mw.title.new local parse = require(template_parser_module).parse local sparse_concat = require("Module:table").sparseConcat local tostring = tostring local type = type local ucfirst = require("Module:string utilities").ucfirst local uupper = require("Module:string utilities").upper local function internal_error(msg) error("Internal error: " .. msg) end local function get_lang(...) local _get_lang = require("Module:languages").getByCode function get_lang(...) return _get_lang(...) or require("Module:languages/errorGetBy").code(...) end return get_lang(...) end local function get_script(...) local _get_script = require("Module:scripts").getByCode function get_script(code) return _get_script(code) or require("Module:languages/error")(code, true, "script code") end return get_script(...) end -- Category object local Category = {} Category.__index = Category function Category:get_originating_info() local originating_info = "" if self._info.originating_label then originating_info = " (originating from label \"" .. self._info.originating_label .. "\" in module [[" .. self._info.originating_module .. "]])" end return originating_info end local valid_keys = list_to_set{"code", "label", "sc", "raw", "args", "also", "called_from_inside", "originating_label", "originating_module"} function Category.new(info) for key in pairs(info) do if not valid_keys[key] then internal_error("The parameter \"" .. key .. "\" was not recognized.") end end local self = setmetatable({}, Category) self._info = info if not self._info.label then internal_error("No label was specified.") end self:initCommon() if not self._data then internal_error("The " .. (self._info.raw and "raw " or "") .. "label \"" .. self._info.label .. "\" does not exist" .. self:get_originating_info() .. ".") end return self end function Category:initCommon() local function patch_args(args) -- This fixes the issue with Scribunto automatically converting keys -- in a table as numbers to strings, which in turn causes a circular -- error for having argument parameter names as numbers as strings. if type(args) ~= "table" then return args end local new_args = {} for k, v in pairs(args) do if type(k) == "string" and string.len(k) < 10 and not string.match(k, "^0") and string.match(k, "^%d+$") then new_args[tonumber(k)] = patch_args(v) else new_args[k] = patch_args(v) end end return new_args end local args_handled = false if self._info.raw then -- Check if the category exists local raw_categories = lang_independent_data["RAW_CATEGORIES"] self._data = raw_categories[self._info.label] if self._data then if self._data.lang then self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end else -- Go through raw handlers local data = { category = self._info.label, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["RAW_HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if self._data then -- Update the label if the handler specified a canonical name for it. if self._data.canonical_name then self._info.canonical_name = self._data.canonical_name end if self._data.lang then if type(self._data.lang) ~= "string" then internal_error("Received non-string value " .. dump(self._data.lang) .. " for self._data.lang, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then if type(self._data.sc) ~= "string" then internal_error("Received non-string value " .. dump(self._data.sc) .. " for self._data.sc, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end end end else -- Already parsed into language + label if self._info.code then self._lang = get_lang(self._info.code) else self._lang = nil end if self._info.sc then self._sc = get_script(self._info.sc) else self._sc = nil end self._info.orig_label = self._info.label if not self._lang then -- Umbrella categories without a preceding language always begin with a capital letter, but the actual label may be -- lowercase (cf. [[:Category:Nouns by language]] with label 'nouns' with per-language [[:Category:English nouns]]; -- but [[:Category:Reddit slang by language]] with label 'Reddit slang' with per-language -- [[:Category:English Reddit slang]]). Since the label is almost always lowercase, we lowercase it for umbrella -- categories, storing the original into `orig_label`, and correct it later if needed. self._info.label = lcfirst(self._info.label) end -- First, check lang-specific labels and handlers if this is not an umbrella category. if self._lang then local objects_with_modules = require(lang_specific_module) local obj, seen = self._lang, {} local object_specific_module_prefix = lang_specific_module_prefix local is_family = false repeat if objects_with_modules[obj:getCode()] then local module = object_specific_module_prefix .. obj:getCode() local labels_and_handlers = require(module) if labels_and_handlers.LABELS then self._data = labels_and_handlers.LABELS[self._info.label] if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module end end if not self._data and labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module break end end end if self._data then break end end seen[obj:getCode()] = true obj = obj:getFamily() if not is_family then is_family = true object_specific_module_prefix = family_specific_module_prefix objects_with_modules = require(family_specific_module) end until not obj or seen[obj:getCode()] end local function fetch_label_data(labels) self._data = labels[self._info.label] -- See comment above about uppercase- vs. lowercase-initial labels, which are indistinguishable -- in umbrella categories. if not self._data then self._data = labels[self._info.orig_label] if self._data then self._info.label = self._info.orig_label end end end -- Then check lang-independent labels. if not self._data then -- lang_independent_data.LABELS should always exist. fetch_label_data(lang_independent_data.LABELS) if not self._data and not self._lang then -- Check family-specific labels for umbrella label. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.LABELS then fetch_label_data(labels_and_handlers.LABELS) if self._data then self._data.module = self._data.module or module break end end end end end -- Then check lang-independent handlers. if not self._data then local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if not self._data and not self._lang then -- Check family-specific labels for umbrella handler. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then self._data.module = self._data.module or module break end end end if self._data then break end end end end end if not args_handled and self._data and self._info.args and next(self._info.args) then local module_text = " (handled in [[" .. (self._data.module or "UNKNOWN").. "]])" local args_text = {} for k, v in pairs(self._info.args) do insert(args_text, k .. "=" .. ((type(v) == "string" or type(v) == "number") and v or dump(v))) end error("poscatboiler label '" .. self._info.label .. "' " .. module_text .. " doesn't accept extra args " .. concat(args_text, ", ")) end if self._sc and not self._lang then internal_error("Umbrella categories cannot have a script specified.") end end function Category:convert_spec_to_string(desc) if not desc then return desc end local desc_type = type(desc) if desc_type == "string" then return desc elseif desc_type == "number" then return tostring(desc) elseif not is_callable(desc) then internal_error("`desc` must be a string, number, function, callable table or nil; received " .. dump(desc)) end desc = desc { lang = self._lang, sc = self._sc, label = self._info.label, raw = self._info.raw, } if not desc then return desc end desc_type = type(desc) if desc_type == "string" then return desc end internal_error("The value returned by `desc` must be a string or nil; received " .. dump(desc)) end local function add_obj_args(args, obj, obj_type) if obj then args[obj_type .. "code"] = obj:getCode() args[obj_type .. "name"] = obj:getCanonicalName() args[obj_type .. "disp"] = obj:getDisplayForm() args[obj_type .. "cat"] = obj:getCategoryName() args[obj_type .. "link"] = obj:makeCategoryLink() end end -- Expands `desc` like a template, passing values for specs like {{{langname}}}. function Category:substitute_template_specs(desc) -- This may end up happening twice but that's OK as the function is (usually) idempotent. -- FIXME: Not idempotent if a preprocessed template returns wikicode. desc = self:convert_spec_to_string(desc) if not desc then return nil end -- Populate the substitution arguments. local args = {} args.umbrella_msg = "ئەمە پۆلێکی گشتگیرە. ھیچ سەروشەیەکی فەرھەنگی تێدا نییە، بەڵکوو تەنیا پۆلەکانی تری تایبەت بە زمانی تێدایە، کە ئەوانیش چەمکە پەیوەندیدارەکان بەو زمانەیان تێدایە." args.umbrella_meta_msg = "This is an umbrella metacategory, covering a general area such as \"lemmas\", \"names\" or \"terms by etymology\". It contains no dictionary entries, but holds only umbrella (\"by language\") categories covering specific subtopics, which in turn contain language-specific categories holding terms in a given language for that same topic." add_obj_args(args, self._lang, "lang") add_obj_args(args, self._sc, "sc") return parse(desc, true):expand(args) end function Category:substitute_template_specs_in_args(args) if not args then return args end local pinfo = {} for k, v in pairs(args) do pinfo[self:substitute_template_specs(k)] = self:substitute_template_specs(v) end return pinfo end function Category:make_new(info) info.originating_label = self._info.label info.originating_module = self._data.module info.called_from_inside = true return Category.new(info) end function Category:getBreadcrumbName() local ret if self._lang or self._info.raw then ret = self._data.breadcrumb or self._data.breadcrumb_and_first_sort_base else ret = self._data.umbrella and (self._data.umbrella.breadcrumb or self._data.umbrella.breadcrumb_and_first_sort_base) end if not ret then ret = self._info.label end if type(ret) ~= "table" then ret = {name = ret} end local name = self:substitute_template_specs(ret.name) local nocap = ret.nocap if self._sc then name = name .. " in " .. self._sc:getDisplayForm() end return name, nocap end local function expand_toc_template_if(template) local template_obj = new_title(template, 10) if template_obj.exists then return expand_template{title = template_obj.text} end return nil end -- Return the textual expansion of the first existing template among the given templates, first performing -- substitutions on the template name such as replacing {{{langcode}}} with the current language's code (if any). -- If no templates exist after expansion, or if nil is passed in, return nil. If a single string is passed in, -- treat it like a one-element list consisting of that string. function Category:get_template_text(templates) if templates == nil then return nil elseif type(templates) ~= "table" then templates = {templates} end for _, template in ipairs(templates) do if template == false then return false end template = self:substitute_template_specs(template) return expand_toc_template_if(template) end return nil end function Category:getTOC(toc_type) -- Type "none" means everything fits on a single page; in that case, display nothing. if toc_type == "none" then return nil end local templates, fallback_templates -- If TOC type is "full" (more than 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template_full` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. look up and expand the `toc_template` templates (normal or umbrella, as above); -- 3. do the default behavior, which is as follows: -- 3a. look up a language-specific "full" template according to the current language (using English if there -- is no current language); -- 3b. look up a script-specific "full" template according to the first script of current language (using English -- if there is no current language); -- 3c. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 3d. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 3e. display nothing. -- -- If TOC type is "normal" (between 200 and 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. do the default behavior, which is as follows: -- 2a. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 2b. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 2c. display nothing. local data_source if self._lang or self._info.raw then data_source = self._data else data_source = self._data.umbrella end if data_source then if toc_type == "full" then templates = data_source.toc_template_full fallback_templates = data_source.toc_template else templates = data_source.toc_template end end local text = self:get_template_text(templates) if text then return text elseif text == false then return nil end text = self:get_template_text(fallback_templates) if text then return text elseif text == false then return nil end local default_toc_templates_to_check = {} local lang, sc = self:getCatfixInfo() local langcode = lang and lang:getCode() or "en" local sccode = sc and sc:getCode() or lang and lang:getScriptCodes()[1] or "Latn" -- FIXME: What is toctemplateprefix used for? local tocname = (self._data.toctemplateprefix or "") .. "categoryTOC" if toc_type == "full" then insert(default_toc_templates_to_check, ("%s-%s/full"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s/full"):format(sccode, tocname)) end insert(default_toc_templates_to_check, ("%s-%s"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s"):format(sccode, tocname)) for _, toc_template in ipairs(default_toc_templates_to_check) do local toc_template_text = expand_toc_template_if(toc_template) if toc_template_text then return toc_template_text end end return nil end function Category:getInfo() return self._info end function Category:getDataModule() return self._data.module end function Category:canBeEmpty() if self._lang or self._info.raw then return self._data.can_be_empty end return self._data.umbrella and self._data.umbrella.can_be_empty end function Category:isHidden() if self._lang or self._info.raw then return self._data.hidden end return self._data.umbrella and self._data.umbrella.hidden end function Category:getCategoryName() if self._info.raw then return self._info.canonical_name or self._info.label elseif self._lang then local ret = self._info.label .. " بە " .. self._lang:getCanonicalName() if self._sc then ret = ret .. " in " .. self._sc:getDisplayForm() end return ucfirst(ret) end local ret = ucfirst(self._info.label) if not (self._data.no_by_language or self._data.umbrella and self._data.umbrella.no_by_language) then ret = ret .. " بەپێی زمان" end return ret end function Category:getTopright() if self._lang or self._info.raw then return self:substitute_template_specs(self._data.topright) end return self._data.umbrella and self:substitute_template_specs(self._data.umbrella.topright) end function Category:display_title(displaytitle, lang) if type(displaytitle) == "string" then displaytitle = self:substitute_template_specs(displaytitle) else displaytitle = displaytitle(self:getCategoryName(), lang) end mw.getCurrentFrame():callParserFunction("DISPLAYTITLE", "Category:" .. displaytitle) end function Category:get_labels_categorizing() local m_labels_utilities = require(labels_utilities_module) local pos_cat_labels, sense_cat_labels, use_tlb pos_cat_labels = m_labels_utilities.find_labels_for_category(self._info.label, "pos", self._lang) local sense_label = self._info.label:match("^(.*) terms$") if sense_label then use_tlb = true else sense_label = self._info.label:match("^terms with (.*) senses$") end if not sense_label then return nil end sense_cat_labels = m_labels_utilities.find_labels_for_category(sense_label, "sense", self._lang) if use_tlb then return m_labels_utilities.format_labels_categorizing(pos_cat_labels, sense_cat_labels, self._lang) end local all_labels = pos_cat_labels for k, v in pairs(sense_cat_labels) do all_labels[k] = v end return m_labels_utilities.format_labels_categorizing(all_labels, nil, self._lang) end -- FIXME: this is clunky. local function remove_lang_params(desc) -- Simply remove a language name/code/category from the beginning of the string, but replace the language name -- in the middle of the string with either "specific languages" or "specific-language" depending on whether the -- language name appears to be an attributive qualifier of another noun or to stand by itself. This may be wrong, -- in which case the category in question should supply its own umbrella description. desc = desc:gsub("^{{{langname}}} ", "") :gsub("{{{langname}}} %(", "specific languages (") :gsub("{{{langname}}}([.,])", "specific languages%1") :gsub("{{{langname}}} ", "specific-language ") :gsub("{{{langdisp}}}", "specific languages") :gsub("{{{langlink}}}", "specific languages") return desc end function Category:getDescription(isChild) -- Allows different text in the list of a category's children local isChild = isChild == "child" if self._lang or self._info.raw then if not isChild and self._data.displaytitle then self:display_title(self._data.displaytitle, self._lang) end if self._sc then return self:getCategoryName() .. "." end local desc = self:substitute_template_specs(self._data.description) if not desc then return nil elseif isChild then return desc end return sparse_concat({ self:substitute_template_specs(self._data.preceding), desc, self:substitute_template_specs(self._data.additional), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end local umbrella = self._data.umbrella if not isChild and umbrella and umbrella.displaytitle then self:display_title(umbrella.displaytitle) end local desc = self:substitute_template_specs(umbrella and umbrella.description) local has_umbrella_desc = not not desc if not desc then desc = self:convert_spec_to_string(self._data.description) if desc then desc = remove_lang_params(desc) desc = lcfirst(desc) desc = desc:gsub("%.$", "") desc = "Categories with " .. desc .. "." else desc = "Categories with " .. self._info.label .. " in various specific languages." end desc = self:substitute_template_specs(desc) end if isChild then return desc end return sparse_concat({ self:substitute_template_specs(umbrella and umbrella.preceding or not has_umbrella_desc and self._data.preceding), desc, self:substitute_template_specs(umbrella and umbrella.additional or not has_umbrella_desc and self._data.additional), self:substitute_template_specs("{{{umbrella_msg}}}"), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end function Category:new_sortkey(sortkey) local sortkey_type = type(sortkey) if sortkey_type == "string" then sortkey = uupper(sortkey) elseif sortkey_type == "table" then function sortkey:makeSortKey() local sort_func = self.sort_func if sort_func ~= nil then return sort_func(self.sort_base) end local lang = self.lang if lang == nil then return self.sort_base end lang = get_lang(lang, nil, true) if lang == nil then return self.sort_base end local sc = self.sc if sc ~= nil then sc = get_script(sc) end return lang:makeSortKey(self.sort_base, sc) end end return sortkey end function Category:inherit_spec(spec, parent_spec, substitute_result) if spec == false then return nil end local retval = spec or parent_spec if substitute_result then retval = self:substitute_template_specs(retval) end return retval end function Category:canonicalize_parents_children(cats, is_children, fallback_sort_base) if not cats then return nil elseif type(cats) == "table" then if cats.name or cats.module then cats = {cats} elseif #cats == 0 then return nil end else cats = {cats} end local ret = {} for _, cat in ipairs(cats) do if type(cat) ~= "table" or not cat.name and not cat.module then cat = {name = cat} end insert(ret, cat) end local is_umbrella = not self._lang and not self._info.raw local table_type = is_children and "extra_children" or "parents" for i, cat in ipairs(ret) do local raw if self._info.raw or is_umbrella then raw = not cat.is_label else raw = cat.raw end local lang = self:inherit_spec(cat.lang, not raw and self._info.code or nil, "substitute") local sc = self:inherit_spec(cat.sc, not raw and self._info.sc or nil, "substitute") -- Get the sortkey. local sortkey = self:inherit_spec(cat.sort, i == 1 and fallback_sort_base and {sort_base = fallback_sort_base} or nil) if type(sortkey) == "table" then sortkey.sort_base = self:substitute_template_specs(sortkey.sort_base) or internal_error("Missing .sort_base in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") if sortkey.sort_func then -- Not allowed to give a lang and/or script if sort_func is given. local bad_spec = sortkey.lang and "lang" or sortkey.sc and "sc" or nil if bad_spec then internal_error("Cannot specify both ." .. bad_spec .. " and .sort_func in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end else sortkey.lang = self:inherit_spec(sortkey.lang, lang, "substitute") sortkey.sc = self:inherit_spec(sortkey.sc, sc, "substitute") end else sortkey = self:substitute_template_specs(sortkey) end local name if cat.module then -- A reference to a category using another category tree module. if not cat.args then internal_error("Missing .args in '" .. table_type .. "' table with module=\"" .. cat.module .. "\" for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end name = require("Module:category tree/" .. cat.module).new(self:substitute_template_specs_in_args(cat.args)) else name = cat.name if not name then internal_error("Missing .name in " .. (is_umbrella and "umbrella " or "") .. "'" .. table_type .. "' table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") elseif type(name) == "string" then -- otherwise, assume it's a category object and use it directly name = self:substitute_template_specs(name) if name:find("^Category:") then -- It's a non-poscatboiler category name. sortkey = sortkey or is_children and name:gsub("^Category:", "") or self:getCategoryName() else -- It's a label. sortkey = sortkey or is_children and name or self._info.label name = self:make_new{ label = name, code = lang, sc = sc, raw = raw, args = self:substitute_template_specs_in_args(cat.args) } end end end sortkey = sortkey or is_children and " " or self._info.label ret[i] = { name = name, description = is_children and self:substitute_template_specs(cat.description) or nil, sort = self:new_sortkey(sortkey) } end return ret end function Category:getParents() local is_umbrella, ret = not self._lang and not self._info.raw if self._sc then local parent1 = self:make_new{code = self._info.code, label = "terms in " .. self._sc:getCanonicalName() .. " script"} local parent2 = self:make_new{code = self._info.code, label = self._info.label, raw = self._info.raw, args = self._info.args} ret = { {name = parent1, sort = self._sc:getCanonicalName()}, {name = parent2, sort = self._sc:getCanonicalName()}, } else local parents, fallback_sort_base if is_umbrella then parents = self._data.umbrella and self._data.umbrella.parents or self._data.umbrella_parents fallback_sort_base = self._data.umbrella and self._data.umbrella.breadcrumb_and_first_sort_base or nil else parents = self._data.parents fallback_sort_base = self._data.breadcrumb_and_first_sort_base end ret = self:canonicalize_parents_children(parents, nil, fallback_sort_base) if not ret then return nil end end local self_cat = self:getCategoryName() for _, parent in ipairs(ret) do local parent_cat = parent.name.getCategoryName and parent.name:getCategoryName() if self_cat == parent_cat then internal_error(("Infinite loop would occur, as parent category '%s' is the same as the child category"):format(self_cat)) end end return ret end function Category:getChildren() local is_umbrella = not self._lang and not self._info.raw local children = self._data.children local ret = {} if not is_umbrella and children then for _, child in ipairs(children) do child = mw.clone(child) if type(child) ~= "table" then child = {name = child} end if not child.sort then child.sort = child.name end -- FIXME, is preserving the script correct? child.name = self:make_new{code = self._info.code, label = child.name, raw = child.raw, sc = self._info.sc} insert(ret, child) end end local extra_children if is_umbrella then extra_children = self._data.umbrella and self._data.umbrella.extra_children else extra_children = self._data.extra_children end extra_children = self:canonicalize_parents_children(extra_children, "children") if extra_children then for _, child in ipairs(extra_children) do insert(ret, child) end end return #ret > 0 and ret or nil end function Category:getUmbrella() local umbrella = self._data.umbrella if umbrella == false or self._info.raw or not self._lang or self._sc then return nil end -- If `umbrella` is a string, use that; otherwise, use the label. return self:make_new({label = type(umbrella) == "string" and umbrella or self._info.label}) end function Category:getAppendix() -- FIXME, this should be customizable. local lang, label = self._lang, self._info.label if self._info.raw or not (lang and label) then return nil end local appendix = make_title(100, lang:getCanonicalName() .. " " .. label) return appendix.exists and appendix.fullText or nil end function Category:getCatfixInfo() if self._lang or self._sc or self._info.raw then local langcode, sccode, lang, sc = self._data.catfix, self._data.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) elseif langcode == nil then -- not false lang = self._lang end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) elseif sccode == nil then -- not false sc = self._sc end return lang, sc elseif not self._data.umbrella then return end -- umbrella local langcode, sccode, lang, sc = self._data.umbrella.catfix, self._data.umbrella.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) end return lang, sc end function Category:getTOCTemplateName() -- This should only be invoked if getTOC() returns true, meaning to do the default algorithm, but getTOC() -- implements its own default algorithm. internal_error("This should never get called") end local export = {} function export.main(info) local self = setmetatable({_info = info}, Category) self:initCommon() return self._data and self or nil end export.new = Category.new return export o45t2ki3sumefh0zo037mj8zxk50lem 36941 36933 2026-08-18T01:27:13Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36933|36933]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36941 Scribunto text/plain local lang_independent_data = require("Module:category tree/data") local lang_specific_module = "Module:category tree/lang" local lang_specific_module_prefix = lang_specific_module .. "/" local family_specific_module = "Module:category tree/fam" local family_specific_module_prefix = family_specific_module .. "/" local labels_utilities_module = "Module:labels/utilities" local template_parser_module = "Module:template parser" local concat = table.concat local dump = mw.dumpObject local expand_template = require("Module:frame").expandTemplate local insert = table.insert local is_callable = require("Module:fun").is_callable local lcfirst = require("Module:string utilities").lcfirst local list_to_set = require("Module:table").listToSet local make_title = mw.title.makeTitle local new_title = mw.title.new local parse = require(template_parser_module).parse local sparse_concat = require("Module:table").sparseConcat local tostring = tostring local type = type local ucfirst = require("Module:string utilities").ucfirst local uupper = require("Module:string utilities").upper local function internal_error(msg) error("Internal error: " .. msg) end local function get_lang(...) local _get_lang = require("Module:languages").getByCode function get_lang(...) return _get_lang(...) or require("Module:languages/errorGetBy").code(...) end return get_lang(...) end local function get_script(...) local _get_script = require("Module:scripts").getByCode function get_script(code) return _get_script(code) or require("Module:languages/error")(code, true, "script code") end return get_script(...) end -- Category object local Category = {} Category.__index = Category function Category:get_originating_info() local originating_info = "" if self._info.originating_label then originating_info = " (originating from label \"" .. self._info.originating_label .. "\" in module [[" .. self._info.originating_module .. "]])" end return originating_info end local valid_keys = list_to_set{"code", "label", "sc", "raw", "args", "also", "called_from_inside", "originating_label", "originating_module"} function Category.new(info) for key in pairs(info) do if not valid_keys[key] then internal_error("The parameter \"" .. key .. "\" was not recognized.") end end local self = setmetatable({}, Category) self._info = info if not self._info.label then internal_error("No label was specified.") end self:initCommon() if not self._data then internal_error("The " .. (self._info.raw and "raw " or "") .. "label \"" .. self._info.label .. "\" does not exist" .. self:get_originating_info() .. ".") end return self end function Category:initCommon() local function patch_args(args) -- This fixes the issue with Scribunto automatically converting keys -- in a table as numbers to strings, which in turn causes a circular -- error for having argument parameter names as numbers as strings. if type(args) ~= "table" then return args end local new_args = {} for k, v in pairs(args) do if type(k) == "string" and string.len(k) < 10 and not string.match(k, "^0") and string.match(k, "^%d+$") then new_args[tonumber(k)] = patch_args(v) else new_args[k] = patch_args(v) end end return new_args end local args_handled = false if self._info.raw then -- Check if the category exists local raw_categories = lang_independent_data["RAW_CATEGORIES"] self._data = raw_categories[self._info.label] if self._data then if self._data.lang then self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end else -- Go through raw handlers local data = { category = self._info.label, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["RAW_HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if self._data then -- Update the label if the handler specified a canonical name for it. if self._data.canonical_name then self._info.canonical_name = self._data.canonical_name end if self._data.lang then if type(self._data.lang) ~= "string" then internal_error("Received non-string value " .. dump(self._data.lang) .. " for self._data.lang, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then if type(self._data.sc) ~= "string" then internal_error("Received non-string value " .. dump(self._data.sc) .. " for self._data.sc, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end end end else -- Already parsed into language + label if self._info.code then self._lang = get_lang(self._info.code) else self._lang = nil end if self._info.sc then self._sc = get_script(self._info.sc) else self._sc = nil end self._info.orig_label = self._info.label if not self._lang then -- Umbrella categories without a preceding language always begin with a capital letter, but the actual label may be -- lowercase (cf. [[:Category:Nouns by language]] with label 'nouns' with per-language [[:Category:English nouns]]; -- but [[:Category:Reddit slang by language]] with label 'Reddit slang' with per-language -- [[:Category:English Reddit slang]]). Since the label is almost always lowercase, we lowercase it for umbrella -- categories, storing the original into `orig_label`, and correct it later if needed. self._info.label = lcfirst(self._info.label) end -- First, check lang-specific labels and handlers if this is not an umbrella category. if self._lang then local objects_with_modules = require(lang_specific_module) local obj, seen = self._lang, {} local object_specific_module_prefix = lang_specific_module_prefix local is_family = false repeat if objects_with_modules[obj:getCode()] then local module = object_specific_module_prefix .. obj:getCode() local labels_and_handlers = require(module) if labels_and_handlers.LABELS then self._data = labels_and_handlers.LABELS[self._info.label] if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module end end if not self._data and labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module break end end end if self._data then break end end seen[obj:getCode()] = true obj = obj:getFamily() if not is_family then is_family = true object_specific_module_prefix = family_specific_module_prefix objects_with_modules = require(family_specific_module) end until not obj or seen[obj:getCode()] end local function fetch_label_data(labels) self._data = labels[self._info.label] -- See comment above about uppercase- vs. lowercase-initial labels, which are indistinguishable -- in umbrella categories. if not self._data then self._data = labels[self._info.orig_label] if self._data then self._info.label = self._info.orig_label end end end -- Then check lang-independent labels. if not self._data then -- lang_independent_data.LABELS should always exist. fetch_label_data(lang_independent_data.LABELS) if not self._data and not self._lang then -- Check family-specific labels for umbrella label. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.LABELS then fetch_label_data(labels_and_handlers.LABELS) if self._data then self._data.module = self._data.module or module break end end end end end -- Then check lang-independent handlers. if not self._data then local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if not self._data and not self._lang then -- Check family-specific labels for umbrella handler. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then self._data.module = self._data.module or module break end end end if self._data then break end end end end end if not args_handled and self._data and self._info.args and next(self._info.args) then local module_text = " (handled in [[" .. (self._data.module or "UNKNOWN").. "]])" local args_text = {} for k, v in pairs(self._info.args) do insert(args_text, k .. "=" .. ((type(v) == "string" or type(v) == "number") and v or dump(v))) end error("poscatboiler label '" .. self._info.label .. "' " .. module_text .. " doesn't accept extra args " .. concat(args_text, ", ")) end if self._sc and not self._lang then internal_error("Umbrella categories cannot have a script specified.") end end function Category:convert_spec_to_string(desc) if not desc then return desc end local desc_type = type(desc) if desc_type == "string" then return desc elseif desc_type == "number" then return tostring(desc) elseif not is_callable(desc) then internal_error("`desc` must be a string, number, function, callable table or nil; received " .. dump(desc)) end desc = desc { lang = self._lang, sc = self._sc, label = self._info.label, raw = self._info.raw, } if not desc then return desc end desc_type = type(desc) if desc_type == "string" then return desc end internal_error("The value returned by `desc` must be a string or nil; received " .. dump(desc)) end local function add_obj_args(args, obj, obj_type) if obj then args[obj_type .. "code"] = obj:getCode() args[obj_type .. "name"] = obj:getCanonicalName() args[obj_type .. "disp"] = obj:getDisplayForm() args[obj_type .. "cat"] = obj:getCategoryName() args[obj_type .. "link"] = obj:makeCategoryLink() end end -- Expands `desc` like a template, passing values for specs like {{{langname}}}. function Category:substitute_template_specs(desc) -- This may end up happening twice but that's OK as the function is (usually) idempotent. -- FIXME: Not idempotent if a preprocessed template returns wikicode. desc = self:convert_spec_to_string(desc) if not desc then return nil end -- Populate the substitution arguments. local args = {} args.umbrella_msg = "ئەمە پۆلێکی گشتگیرە. ھیچ سەروشەیەکی فەرھەنگی تێدا نییە، بەڵکوو تەنیا پۆلەکانی تری تایبەت بە زمانی تێدایە، کە ئەوانیش چەمکە پەیوەندیدارەکان بەو زمانەیان تێدایە." args.umbrella_meta_msg = "This is an umbrella metacategory, covering a general area such as \"lemmas\", \"names\" or \"terms by etymology\". It contains no dictionary entries, but holds only umbrella (\"by language\") categories covering specific subtopics, which in turn contain language-specific categories holding terms in a given language for that same topic." add_obj_args(args, self._lang, "lang") add_obj_args(args, self._sc, "sc") return parse(desc, true):expand(args) end function Category:substitute_template_specs_in_args(args) if not args then return args end local pinfo = {} for k, v in pairs(args) do pinfo[self:substitute_template_specs(k)] = self:substitute_template_specs(v) end return pinfo end function Category:make_new(info) info.originating_label = self._info.label info.originating_module = self._data.module info.called_from_inside = true return Category.new(info) end function Category:getBreadcrumbName() local ret if self._lang or self._info.raw then ret = self._data.breadcrumb or self._data.breadcrumb_and_first_sort_base else ret = self._data.umbrella and (self._data.umbrella.breadcrumb or self._data.umbrella.breadcrumb_and_first_sort_base) end if not ret then ret = self._info.label end if type(ret) ~= "table" then ret = {name = ret} end local name = self:substitute_template_specs(ret.name) local nocap = ret.nocap if self._sc then name = name .. " in " .. self._sc:getDisplayForm() end return name, nocap end local function expand_toc_template_if(template) local template_obj = new_title(template, 10) if template_obj.exists then return expand_template{title = template_obj.text} end return nil end -- Return the textual expansion of the first existing template among the given templates, first performing -- substitutions on the template name such as replacing {{{langcode}}} with the current language's code (if any). -- If no templates exist after expansion, or if nil is passed in, return nil. If a single string is passed in, -- treat it like a one-element list consisting of that string. function Category:get_template_text(templates) if templates == nil then return nil elseif type(templates) ~= "table" then templates = {templates} end for _, template in ipairs(templates) do if template == false then return false end template = self:substitute_template_specs(template) return expand_toc_template_if(template) end return nil end function Category:getTOC(toc_type) -- Type "none" means everything fits on a single page; in that case, display nothing. if toc_type == "none" then return nil end local templates, fallback_templates -- If TOC type is "full" (more than 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template_full` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. look up and expand the `toc_template` templates (normal or umbrella, as above); -- 3. do the default behavior, which is as follows: -- 3a. look up a language-specific "full" template according to the current language (using English if there -- is no current language); -- 3b. look up a script-specific "full" template according to the first script of current language (using English -- if there is no current language); -- 3c. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 3d. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 3e. display nothing. -- -- If TOC type is "normal" (between 200 and 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. do the default behavior, which is as follows: -- 2a. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 2b. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 2c. display nothing. local data_source if self._lang or self._info.raw then data_source = self._data else data_source = self._data.umbrella end if data_source then if toc_type == "full" then templates = data_source.toc_template_full fallback_templates = data_source.toc_template else templates = data_source.toc_template end end local text = self:get_template_text(templates) if text then return text elseif text == false then return nil end text = self:get_template_text(fallback_templates) if text then return text elseif text == false then return nil end local default_toc_templates_to_check = {} local lang, sc = self:getCatfixInfo() local langcode = lang and lang:getCode() or "en" local sccode = sc and sc:getCode() or lang and lang:getScriptCodes()[1] or "Latn" -- FIXME: What is toctemplateprefix used for? local tocname = (self._data.toctemplateprefix or "") .. "categoryTOC" if toc_type == "full" then insert(default_toc_templates_to_check, ("%s-%s/full"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s/full"):format(sccode, tocname)) end insert(default_toc_templates_to_check, ("%s-%s"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s"):format(sccode, tocname)) for _, toc_template in ipairs(default_toc_templates_to_check) do local toc_template_text = expand_toc_template_if(toc_template) if toc_template_text then return toc_template_text end end return nil end function Category:getInfo() return self._info end function Category:getDataModule() return self._data.module end function Category:canBeEmpty() if self._lang or self._info.raw then return self._data.can_be_empty end return self._data.umbrella and self._data.umbrella.can_be_empty end function Category:isHidden() if self._lang or self._info.raw then return self._data.hidden end return self._data.umbrella and self._data.umbrella.hidden end function Category:getCategoryName() if self._info.raw then return self._info.canonical_name or self._info.label elseif self._lang then local ret = self._info.label .. " بە " .. self._lang:getCanonicalName() if self._sc then ret = ret .. " in " .. self._sc:getDisplayForm() end return ucfirst(ret) end local ret = ucfirst(self._info.label) if not (self._data.no_by_language or self._data.umbrella and self._data.umbrella.no_by_language) then ret = ret .. " by language" end return ret end function Category:getTopright() if self._lang or self._info.raw then return self:substitute_template_specs(self._data.topright) end return self._data.umbrella and self:substitute_template_specs(self._data.umbrella.topright) end function Category:display_title(displaytitle, lang) if type(displaytitle) == "string" then displaytitle = self:substitute_template_specs(displaytitle) else displaytitle = displaytitle(self:getCategoryName(), lang) end mw.getCurrentFrame():callParserFunction("DISPLAYTITLE", "Category:" .. displaytitle) end function Category:get_labels_categorizing() local m_labels_utilities = require(labels_utilities_module) local pos_cat_labels, sense_cat_labels, use_tlb pos_cat_labels = m_labels_utilities.find_labels_for_category(self._info.label, "pos", self._lang) local sense_label = self._info.label:match("^(.*) terms$") if sense_label then use_tlb = true else sense_label = self._info.label:match("^terms with (.*) senses$") end if not sense_label then return nil end sense_cat_labels = m_labels_utilities.find_labels_for_category(sense_label, "sense", self._lang) if use_tlb then return m_labels_utilities.format_labels_categorizing(pos_cat_labels, sense_cat_labels, self._lang) end local all_labels = pos_cat_labels for k, v in pairs(sense_cat_labels) do all_labels[k] = v end return m_labels_utilities.format_labels_categorizing(all_labels, nil, self._lang) end -- FIXME: this is clunky. local function remove_lang_params(desc) -- Simply remove a language name/code/category from the beginning of the string, but replace the language name -- in the middle of the string with either "specific languages" or "specific-language" depending on whether the -- language name appears to be an attributive qualifier of another noun or to stand by itself. This may be wrong, -- in which case the category in question should supply its own umbrella description. desc = desc:gsub("^{{{langname}}} ", "") :gsub("{{{langname}}} %(", "specific languages (") :gsub("{{{langname}}}([.,])", "specific languages%1") :gsub("{{{langname}}} ", "specific-language ") :gsub("{{{langdisp}}}", "specific languages") :gsub("{{{langlink}}}", "specific languages") return desc end function Category:getDescription(isChild) -- Allows different text in the list of a category's children local isChild = isChild == "child" if self._lang or self._info.raw then if not isChild and self._data.displaytitle then self:display_title(self._data.displaytitle, self._lang) end if self._sc then return self:getCategoryName() .. "." end local desc = self:substitute_template_specs(self._data.description) if not desc then return nil elseif isChild then return desc end return sparse_concat({ self:substitute_template_specs(self._data.preceding), desc, self:substitute_template_specs(self._data.additional), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end local umbrella = self._data.umbrella if not isChild and umbrella and umbrella.displaytitle then self:display_title(umbrella.displaytitle) end local desc = self:substitute_template_specs(umbrella and umbrella.description) local has_umbrella_desc = not not desc if not desc then desc = self:convert_spec_to_string(self._data.description) if desc then desc = remove_lang_params(desc) desc = lcfirst(desc) desc = desc:gsub("%.$", "") desc = "Categories with " .. desc .. "." else desc = "Categories with " .. self._info.label .. " in various specific languages." end desc = self:substitute_template_specs(desc) end if isChild then return desc end return sparse_concat({ self:substitute_template_specs(umbrella and umbrella.preceding or not has_umbrella_desc and self._data.preceding), desc, self:substitute_template_specs(umbrella and umbrella.additional or not has_umbrella_desc and self._data.additional), self:substitute_template_specs("{{{umbrella_msg}}}"), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end function Category:new_sortkey(sortkey) local sortkey_type = type(sortkey) if sortkey_type == "string" then sortkey = uupper(sortkey) elseif sortkey_type == "table" then function sortkey:makeSortKey() local sort_func = self.sort_func if sort_func ~= nil then return sort_func(self.sort_base) end local lang = self.lang if lang == nil then return self.sort_base end lang = get_lang(lang, nil, true) if lang == nil then return self.sort_base end local sc = self.sc if sc ~= nil then sc = get_script(sc) end return lang:makeSortKey(self.sort_base, sc) end end return sortkey end function Category:inherit_spec(spec, parent_spec, substitute_result) if spec == false then return nil end local retval = spec or parent_spec if substitute_result then retval = self:substitute_template_specs(retval) end return retval end function Category:canonicalize_parents_children(cats, is_children, fallback_sort_base) if not cats then return nil elseif type(cats) == "table" then if cats.name or cats.module then cats = {cats} elseif #cats == 0 then return nil end else cats = {cats} end local ret = {} for _, cat in ipairs(cats) do if type(cat) ~= "table" or not cat.name and not cat.module then cat = {name = cat} end insert(ret, cat) end local is_umbrella = not self._lang and not self._info.raw local table_type = is_children and "extra_children" or "parents" for i, cat in ipairs(ret) do local raw if self._info.raw or is_umbrella then raw = not cat.is_label else raw = cat.raw end local lang = self:inherit_spec(cat.lang, not raw and self._info.code or nil, "substitute") local sc = self:inherit_spec(cat.sc, not raw and self._info.sc or nil, "substitute") -- Get the sortkey. local sortkey = self:inherit_spec(cat.sort, i == 1 and fallback_sort_base and {sort_base = fallback_sort_base} or nil) if type(sortkey) == "table" then sortkey.sort_base = self:substitute_template_specs(sortkey.sort_base) or internal_error("Missing .sort_base in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") if sortkey.sort_func then -- Not allowed to give a lang and/or script if sort_func is given. local bad_spec = sortkey.lang and "lang" or sortkey.sc and "sc" or nil if bad_spec then internal_error("Cannot specify both ." .. bad_spec .. " and .sort_func in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end else sortkey.lang = self:inherit_spec(sortkey.lang, lang, "substitute") sortkey.sc = self:inherit_spec(sortkey.sc, sc, "substitute") end else sortkey = self:substitute_template_specs(sortkey) end local name if cat.module then -- A reference to a category using another category tree module. if not cat.args then internal_error("Missing .args in '" .. table_type .. "' table with module=\"" .. cat.module .. "\" for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end name = require("Module:category tree/" .. cat.module).new(self:substitute_template_specs_in_args(cat.args)) else name = cat.name if not name then internal_error("Missing .name in " .. (is_umbrella and "umbrella " or "") .. "'" .. table_type .. "' table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") elseif type(name) == "string" then -- otherwise, assume it's a category object and use it directly name = self:substitute_template_specs(name) if name:find("^Category:") then -- It's a non-poscatboiler category name. sortkey = sortkey or is_children and name:gsub("^Category:", "") or self:getCategoryName() else -- It's a label. sortkey = sortkey or is_children and name or self._info.label name = self:make_new{ label = name, code = lang, sc = sc, raw = raw, args = self:substitute_template_specs_in_args(cat.args) } end end end sortkey = sortkey or is_children and " " or self._info.label ret[i] = { name = name, description = is_children and self:substitute_template_specs(cat.description) or nil, sort = self:new_sortkey(sortkey) } end return ret end function Category:getParents() local is_umbrella, ret = not self._lang and not self._info.raw if self._sc then local parent1 = self:make_new{code = self._info.code, label = "terms in " .. self._sc:getCanonicalName() .. " script"} local parent2 = self:make_new{code = self._info.code, label = self._info.label, raw = self._info.raw, args = self._info.args} ret = { {name = parent1, sort = self._sc:getCanonicalName()}, {name = parent2, sort = self._sc:getCanonicalName()}, } else local parents, fallback_sort_base if is_umbrella then parents = self._data.umbrella and self._data.umbrella.parents or self._data.umbrella_parents fallback_sort_base = self._data.umbrella and self._data.umbrella.breadcrumb_and_first_sort_base or nil else parents = self._data.parents fallback_sort_base = self._data.breadcrumb_and_first_sort_base end ret = self:canonicalize_parents_children(parents, nil, fallback_sort_base) if not ret then return nil end end local self_cat = self:getCategoryName() for _, parent in ipairs(ret) do local parent_cat = parent.name.getCategoryName and parent.name:getCategoryName() if self_cat == parent_cat then internal_error(("Infinite loop would occur, as parent category '%s' is the same as the child category"):format(self_cat)) end end return ret end function Category:getChildren() local is_umbrella = not self._lang and not self._info.raw local children = self._data.children local ret = {} if not is_umbrella and children then for _, child in ipairs(children) do child = mw.clone(child) if type(child) ~= "table" then child = {name = child} end if not child.sort then child.sort = child.name end -- FIXME, is preserving the script correct? child.name = self:make_new{code = self._info.code, label = child.name, raw = child.raw, sc = self._info.sc} insert(ret, child) end end local extra_children if is_umbrella then extra_children = self._data.umbrella and self._data.umbrella.extra_children else extra_children = self._data.extra_children end extra_children = self:canonicalize_parents_children(extra_children, "children") if extra_children then for _, child in ipairs(extra_children) do insert(ret, child) end end return #ret > 0 and ret or nil end function Category:getUmbrella() local umbrella = self._data.umbrella if umbrella == false or self._info.raw or not self._lang or self._sc then return nil end -- If `umbrella` is a string, use that; otherwise, use the label. return self:make_new({label = type(umbrella) == "string" and umbrella or self._info.label}) end function Category:getAppendix() -- FIXME, this should be customizable. local lang, label = self._lang, self._info.label if self._info.raw or not (lang and label) then return nil end local appendix = make_title(100, lang:getCanonicalName() .. " " .. label) return appendix.exists and appendix.fullText or nil end function Category:getCatfixInfo() if self._lang or self._sc or self._info.raw then local langcode, sccode, lang, sc = self._data.catfix, self._data.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) elseif langcode == nil then -- not false lang = self._lang end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) elseif sccode == nil then -- not false sc = self._sc end return lang, sc elseif not self._data.umbrella then return end -- umbrella local langcode, sccode, lang, sc = self._data.umbrella.catfix, self._data.umbrella.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) end return lang, sc end function Category:getTOCTemplateName() -- This should only be invoked if getTOC() returns true, meaning to do the default algorithm, but getTOC() -- implements its own default algorithm. internal_error("This should never get called") end local export = {} function export.main(info) local self = setmetatable({_info = info}, Category) self:initCommon() return self._data and self or nil end export.new = Category.new return export 2en0fruvknv7e2aj4r2968jkh2854zh 36942 36941 2026-08-18T01:28:40Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36941|36941]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36942 Scribunto text/plain local lang_independent_data = require("Module:category tree/data") local lang_specific_module = "Module:category tree/lang" local lang_specific_module_prefix = lang_specific_module .. "/" local family_specific_module = "Module:category tree/fam" local family_specific_module_prefix = family_specific_module .. "/" local labels_utilities_module = "Module:labels/utilities" local template_parser_module = "Module:template parser" local concat = table.concat local dump = mw.dumpObject local expand_template = require("Module:frame").expandTemplate local insert = table.insert local is_callable = require("Module:fun").is_callable local lcfirst = require("Module:string utilities").lcfirst local list_to_set = require("Module:table").listToSet local make_title = mw.title.makeTitle local new_title = mw.title.new local parse = require(template_parser_module).parse local sparse_concat = require("Module:table").sparseConcat local tostring = tostring local type = type local ucfirst = require("Module:string utilities").ucfirst local uupper = require("Module:string utilities").upper local function internal_error(msg) error("Internal error: " .. msg) end local function get_lang(...) local _get_lang = require("Module:languages").getByCode function get_lang(...) return _get_lang(...) or require("Module:languages/errorGetBy").code(...) end return get_lang(...) end local function get_script(...) local _get_script = require("Module:scripts").getByCode function get_script(code) return _get_script(code) or require("Module:languages/error")(code, true, "script code") end return get_script(...) end -- Category object local Category = {} Category.__index = Category function Category:get_originating_info() local originating_info = "" if self._info.originating_label then originating_info = " (originating from label \"" .. self._info.originating_label .. "\" in module [[" .. self._info.originating_module .. "]])" end return originating_info end local valid_keys = list_to_set{"code", "label", "sc", "raw", "args", "also", "called_from_inside", "originating_label", "originating_module"} function Category.new(info) for key in pairs(info) do if not valid_keys[key] then internal_error("The parameter \"" .. key .. "\" was not recognized.") end end local self = setmetatable({}, Category) self._info = info if not self._info.label then internal_error("No label was specified.") end self:initCommon() if not self._data then internal_error("The " .. (self._info.raw and "raw " or "") .. "label \"" .. self._info.label .. "\" does not exist" .. self:get_originating_info() .. ".") end return self end function Category:initCommon() local function patch_args(args) -- This fixes the issue with Scribunto automatically converting keys -- in a table as numbers to strings, which in turn causes a circular -- error for having argument parameter names as numbers as strings. if type(args) ~= "table" then return args end local new_args = {} for k, v in pairs(args) do if type(k) == "string" and string.len(k) < 10 and not string.match(k, "^0") and string.match(k, "^%d+$") then new_args[tonumber(k)] = patch_args(v) else new_args[k] = patch_args(v) end end return new_args end local args_handled = false if self._info.raw then -- Check if the category exists local raw_categories = lang_independent_data["RAW_CATEGORIES"] self._data = raw_categories[self._info.label] if self._data then if self._data.lang then self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end else -- Go through raw handlers local data = { category = self._info.label, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["RAW_HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if self._data then -- Update the label if the handler specified a canonical name for it. if self._data.canonical_name then self._info.canonical_name = self._data.canonical_name end if self._data.lang then if type(self._data.lang) ~= "string" then internal_error("Received non-string value " .. dump(self._data.lang) .. " for self._data.lang, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._lang = get_lang(self._data.lang) self._info.code = self._lang:getCode() end if self._data.sc then if type(self._data.sc) ~= "string" then internal_error("Received non-string value " .. dump(self._data.sc) .. " for self._data.sc, label \"" .. self._info.label .. "\"" .. self:get_originating_info() .. ".") end self._sc = get_script(self._data.sc) self._info.sc = self._sc:getCode() end end end else -- Already parsed into language + label if self._info.code then self._lang = get_lang(self._info.code) else self._lang = nil end if self._info.sc then self._sc = get_script(self._info.sc) else self._sc = nil end self._info.orig_label = self._info.label if not self._lang then -- Umbrella categories without a preceding language always begin with a capital letter, but the actual label may be -- lowercase (cf. [[:Category:Nouns by language]] with label 'nouns' with per-language [[:Category:English nouns]]; -- but [[:Category:Reddit slang by language]] with label 'Reddit slang' with per-language -- [[:Category:English Reddit slang]]). Since the label is almost always lowercase, we lowercase it for umbrella -- categories, storing the original into `orig_label`, and correct it later if needed. self._info.label = lcfirst(self._info.label) end -- First, check lang-specific labels and handlers if this is not an umbrella category. if self._lang then local objects_with_modules = require(lang_specific_module) local obj, seen = self._lang, {} local object_specific_module_prefix = lang_specific_module_prefix local is_family = false repeat if objects_with_modules[obj:getCode()] then local module = object_specific_module_prefix .. obj:getCode() local labels_and_handlers = require(module) if labels_and_handlers.LABELS then self._data = labels_and_handlers.LABELS[self._info.label] if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module end end if not self._data and labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then if not is_family and self._data.umbrella == nil and self._data.umbrella_parents == nil then self._data.umbrella = false end self._data.module = self._data.module or module break end end end if self._data then break end end seen[obj:getCode()] = true obj = obj:getFamily() if not is_family then is_family = true object_specific_module_prefix = family_specific_module_prefix objects_with_modules = require(family_specific_module) end until not obj or seen[obj:getCode()] end local function fetch_label_data(labels) self._data = labels[self._info.label] -- See comment above about uppercase- vs. lowercase-initial labels, which are indistinguishable -- in umbrella categories. if not self._data then self._data = labels[self._info.orig_label] if self._data then self._info.label = self._info.orig_label end end end -- Then check lang-independent labels. if not self._data then -- lang_independent_data.LABELS should always exist. fetch_label_data(lang_independent_data.LABELS) if not self._data and not self._lang then -- Check family-specific labels for umbrella label. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.LABELS then fetch_label_data(labels_and_handlers.LABELS) if self._data then self._data.module = self._data.module or module break end end end end end -- Then check lang-independent handlers. if not self._data then local data = { label = self._info.label, lang = self._lang, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } for _, handler in ipairs(lang_independent_data["HANDLERS"]) do self._data, args_handled = handler.handler(data) if self._data then self._data.module = self._data.module or handler.module break end end if not self._data and not self._lang then -- Check family-specific labels for umbrella handler. local families_with_modules = require(family_specific_module) for famcode, _ in pairs(families_with_modules) do local module = family_specific_module_prefix .. famcode local labels_and_handlers = require(module) if labels_and_handlers.HANDLERS then for _, handler in ipairs(labels_and_handlers.HANDLERS) do local data = { label = self._info.label, sc = self._sc, args = patch_args(self._info.args) or {}, called_from_inside = self._info.called_from_inside, } self._data, args_handled = handler(data) if self._data then self._data.module = self._data.module or module break end end end if self._data then break end end end end end if not args_handled and self._data and self._info.args and next(self._info.args) then local module_text = " (handled in [[" .. (self._data.module or "UNKNOWN").. "]])" local args_text = {} for k, v in pairs(self._info.args) do insert(args_text, k .. "=" .. ((type(v) == "string" or type(v) == "number") and v or dump(v))) end error("poscatboiler label '" .. self._info.label .. "' " .. module_text .. " doesn't accept extra args " .. concat(args_text, ", ")) end if self._sc and not self._lang then internal_error("Umbrella categories cannot have a script specified.") end end function Category:convert_spec_to_string(desc) if not desc then return desc end local desc_type = type(desc) if desc_type == "string" then return desc elseif desc_type == "number" then return tostring(desc) elseif not is_callable(desc) then internal_error("`desc` must be a string, number, function, callable table or nil; received " .. dump(desc)) end desc = desc { lang = self._lang, sc = self._sc, label = self._info.label, raw = self._info.raw, } if not desc then return desc end desc_type = type(desc) if desc_type == "string" then return desc end internal_error("The value returned by `desc` must be a string or nil; received " .. dump(desc)) end local function add_obj_args(args, obj, obj_type) if obj then args[obj_type .. "code"] = obj:getCode() args[obj_type .. "name"] = obj:getCanonicalName() args[obj_type .. "disp"] = obj:getDisplayForm() args[obj_type .. "cat"] = obj:getCategoryName() args[obj_type .. "link"] = obj:makeCategoryLink() end end -- Expands `desc` like a template, passing values for specs like {{{langname}}}. function Category:substitute_template_specs(desc) -- This may end up happening twice but that's OK as the function is (usually) idempotent. -- FIXME: Not idempotent if a preprocessed template returns wikicode. desc = self:convert_spec_to_string(desc) if not desc then return nil end -- Populate the substitution arguments. local args = {} args.umbrella_msg = "ئەمە پۆلێکی گشتگیرە. ھیچ سەروشەیەکی فەرھەنگی تێدا نییە، بەڵکوو تەنیا پۆلەکانی تری تایبەت بە زمانی تێدایە، کە ئەوانیش چەمکە پەیوەندیدارەکان بەو زمانەیان تێدایە." args.umbrella_meta_msg = "This is an umbrella metacategory, covering a general area such as \"lemmas\", \"names\" or \"terms by etymology\". It contains no dictionary entries, but holds only umbrella (\"by language\") categories covering specific subtopics, which in turn contain language-specific categories holding terms in a given language for that same topic." add_obj_args(args, self._lang, "lang") add_obj_args(args, self._sc, "sc") return parse(desc, true):expand(args) end function Category:substitute_template_specs_in_args(args) if not args then return args end local pinfo = {} for k, v in pairs(args) do pinfo[self:substitute_template_specs(k)] = self:substitute_template_specs(v) end return pinfo end function Category:make_new(info) info.originating_label = self._info.label info.originating_module = self._data.module info.called_from_inside = true return Category.new(info) end function Category:getBreadcrumbName() local ret if self._lang or self._info.raw then ret = self._data.breadcrumb or self._data.breadcrumb_and_first_sort_base else ret = self._data.umbrella and (self._data.umbrella.breadcrumb or self._data.umbrella.breadcrumb_and_first_sort_base) end if not ret then ret = self._info.label end if type(ret) ~= "table" then ret = {name = ret} end local name = self:substitute_template_specs(ret.name) local nocap = ret.nocap if self._sc then name = name .. " in " .. self._sc:getDisplayForm() end return name, nocap end local function expand_toc_template_if(template) local template_obj = new_title(template, 10) if template_obj.exists then return expand_template{title = template_obj.text} end return nil end -- Return the textual expansion of the first existing template among the given templates, first performing -- substitutions on the template name such as replacing {{{langcode}}} with the current language's code (if any). -- If no templates exist after expansion, or if nil is passed in, return nil. If a single string is passed in, -- treat it like a one-element list consisting of that string. function Category:get_template_text(templates) if templates == nil then return nil elseif type(templates) ~= "table" then templates = {templates} end for _, template in ipairs(templates) do if template == false then return false end template = self:substitute_template_specs(template) return expand_toc_template_if(template) end return nil end function Category:getTOC(toc_type) -- Type "none" means everything fits on a single page; in that case, display nothing. if toc_type == "none" then return nil end local templates, fallback_templates -- If TOC type is "full" (more than 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template_full` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. look up and expand the `toc_template` templates (normal or umbrella, as above); -- 3. do the default behavior, which is as follows: -- 3a. look up a language-specific "full" template according to the current language (using English if there -- is no current language); -- 3b. look up a script-specific "full" template according to the first script of current language (using English -- if there is no current language); -- 3c. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 3d. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 3e. display nothing. -- -- If TOC type is "normal" (between 200 and 2500 entries), do the following, in order: -- 1. look up and expand the `toc_template` templates (normal or umbrella, depending on whether there is -- a current language); -- 2. do the default behavior, which is as follows: -- 2a. look up a language-specific "normal" template according to the current language (using English if there -- is no current language); -- 2b. look up a script-specific "normal" template according to the first script of the current language (using -- English if there is no current language); -- 2c. display nothing. local data_source if self._lang or self._info.raw then data_source = self._data else data_source = self._data.umbrella end if data_source then if toc_type == "full" then templates = data_source.toc_template_full fallback_templates = data_source.toc_template else templates = data_source.toc_template end end local text = self:get_template_text(templates) if text then return text elseif text == false then return nil end text = self:get_template_text(fallback_templates) if text then return text elseif text == false then return nil end local default_toc_templates_to_check = {} local lang, sc = self:getCatfixInfo() local langcode = lang and lang:getCode() or "en" local sccode = sc and sc:getCode() or lang and lang:getScriptCodes()[1] or "Latn" -- FIXME: What is toctemplateprefix used for? local tocname = (self._data.toctemplateprefix or "") .. "categoryTOC" if toc_type == "full" then insert(default_toc_templates_to_check, ("%s-%s/full"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s/full"):format(sccode, tocname)) end insert(default_toc_templates_to_check, ("%s-%s"):format(langcode, tocname)) insert(default_toc_templates_to_check, ("%s-%s"):format(sccode, tocname)) for _, toc_template in ipairs(default_toc_templates_to_check) do local toc_template_text = expand_toc_template_if(toc_template) if toc_template_text then return toc_template_text end end return nil end function Category:getInfo() return self._info end function Category:getDataModule() return self._data.module end function Category:canBeEmpty() if self._lang or self._info.raw then return self._data.can_be_empty end return self._data.umbrella and self._data.umbrella.can_be_empty end function Category:isHidden() if self._lang or self._info.raw then return self._data.hidden end return self._data.umbrella and self._data.umbrella.hidden end function Category:getCategoryName() if self._info.raw then return self._info.canonical_name or self._info.label elseif self._lang then local ret = self._info.label .. " بە " .. self._lang:getCanonicalName() if self._sc then ret = ret .. " in " .. self._sc:getDisplayForm() end return ucfirst(ret) end local ret = ucfirst(self._info.label) if not (self._data.no_by_language or self._data.umbrella and self._data.umbrella.no_by_language) then ret = ret .. " بەپێی زمان" end return ret end function Category:getTopright() if self._lang or self._info.raw then return self:substitute_template_specs(self._data.topright) end return self._data.umbrella and self:substitute_template_specs(self._data.umbrella.topright) end function Category:display_title(displaytitle, lang) if type(displaytitle) == "string" then displaytitle = self:substitute_template_specs(displaytitle) else displaytitle = displaytitle(self:getCategoryName(), lang) end mw.getCurrentFrame():callParserFunction("DISPLAYTITLE", "Category:" .. displaytitle) end function Category:get_labels_categorizing() local m_labels_utilities = require(labels_utilities_module) local pos_cat_labels, sense_cat_labels, use_tlb pos_cat_labels = m_labels_utilities.find_labels_for_category(self._info.label, "pos", self._lang) local sense_label = self._info.label:match("^(.*) terms$") if sense_label then use_tlb = true else sense_label = self._info.label:match("^terms with (.*) senses$") end if not sense_label then return nil end sense_cat_labels = m_labels_utilities.find_labels_for_category(sense_label, "sense", self._lang) if use_tlb then return m_labels_utilities.format_labels_categorizing(pos_cat_labels, sense_cat_labels, self._lang) end local all_labels = pos_cat_labels for k, v in pairs(sense_cat_labels) do all_labels[k] = v end return m_labels_utilities.format_labels_categorizing(all_labels, nil, self._lang) end -- FIXME: this is clunky. local function remove_lang_params(desc) -- Simply remove a language name/code/category from the beginning of the string, but replace the language name -- in the middle of the string with either "specific languages" or "specific-language" depending on whether the -- language name appears to be an attributive qualifier of another noun or to stand by itself. This may be wrong, -- in which case the category in question should supply its own umbrella description. desc = desc:gsub("^{{{langname}}} ", "") :gsub("{{{langname}}} %(", "specific languages (") :gsub("{{{langname}}}([.,])", "specific languages%1") :gsub("{{{langname}}} ", "specific-language ") :gsub("{{{langdisp}}}", "specific languages") :gsub("{{{langlink}}}", "specific languages") return desc end function Category:getDescription(isChild) -- Allows different text in the list of a category's children local isChild = isChild == "child" if self._lang or self._info.raw then if not isChild and self._data.displaytitle then self:display_title(self._data.displaytitle, self._lang) end if self._sc then return self:getCategoryName() .. "." end local desc = self:substitute_template_specs(self._data.description) if not desc then return nil elseif isChild then return desc end return sparse_concat({ self:substitute_template_specs(self._data.preceding), desc, self:substitute_template_specs(self._data.additional), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end local umbrella = self._data.umbrella if not isChild and umbrella and umbrella.displaytitle then self:display_title(umbrella.displaytitle) end local desc = self:substitute_template_specs(umbrella and umbrella.description) local has_umbrella_desc = not not desc if not desc then desc = self:convert_spec_to_string(self._data.description) if desc then desc = remove_lang_params(desc) desc = lcfirst(desc) desc = desc:gsub("%.$", "") desc = "Categories with " .. desc .. "." else desc = "Categories with " .. self._info.label .. " in various specific languages." end desc = self:substitute_template_specs(desc) end if isChild then return desc end return sparse_concat({ self:substitute_template_specs(umbrella and umbrella.preceding or not has_umbrella_desc and self._data.preceding), desc, self:substitute_template_specs(umbrella and umbrella.additional or not has_umbrella_desc and self._data.additional), self:substitute_template_specs("{{{umbrella_msg}}}"), self:substitute_template_specs(self:get_labels_categorizing()), }, "\n\n") end function Category:new_sortkey(sortkey) local sortkey_type = type(sortkey) if sortkey_type == "string" then sortkey = uupper(sortkey) elseif sortkey_type == "table" then function sortkey:makeSortKey() local sort_func = self.sort_func if sort_func ~= nil then return sort_func(self.sort_base) end local lang = self.lang if lang == nil then return self.sort_base end lang = get_lang(lang, nil, true) if lang == nil then return self.sort_base end local sc = self.sc if sc ~= nil then sc = get_script(sc) end return lang:makeSortKey(self.sort_base, sc) end end return sortkey end function Category:inherit_spec(spec, parent_spec, substitute_result) if spec == false then return nil end local retval = spec or parent_spec if substitute_result then retval = self:substitute_template_specs(retval) end return retval end function Category:canonicalize_parents_children(cats, is_children, fallback_sort_base) if not cats then return nil elseif type(cats) == "table" then if cats.name or cats.module then cats = {cats} elseif #cats == 0 then return nil end else cats = {cats} end local ret = {} for _, cat in ipairs(cats) do if type(cat) ~= "table" or not cat.name and not cat.module then cat = {name = cat} end insert(ret, cat) end local is_umbrella = not self._lang and not self._info.raw local table_type = is_children and "extra_children" or "parents" for i, cat in ipairs(ret) do local raw if self._info.raw or is_umbrella then raw = not cat.is_label else raw = cat.raw end local lang = self:inherit_spec(cat.lang, not raw and self._info.code or nil, "substitute") local sc = self:inherit_spec(cat.sc, not raw and self._info.sc or nil, "substitute") -- Get the sortkey. local sortkey = self:inherit_spec(cat.sort, i == 1 and fallback_sort_base and {sort_base = fallback_sort_base} or nil) if type(sortkey) == "table" then sortkey.sort_base = self:substitute_template_specs(sortkey.sort_base) or internal_error("Missing .sort_base in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") if sortkey.sort_func then -- Not allowed to give a lang and/or script if sort_func is given. local bad_spec = sortkey.lang and "lang" or sortkey.sc and "sc" or nil if bad_spec then internal_error("Cannot specify both ." .. bad_spec .. " and .sort_func in '" .. table_type .. "' .sort table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end else sortkey.lang = self:inherit_spec(sortkey.lang, lang, "substitute") sortkey.sc = self:inherit_spec(sortkey.sc, sc, "substitute") end else sortkey = self:substitute_template_specs(sortkey) end local name if cat.module then -- A reference to a category using another category tree module. if not cat.args then internal_error("Missing .args in '" .. table_type .. "' table with module=\"" .. cat.module .. "\" for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") end name = require("Module:category tree/" .. cat.module).new(self:substitute_template_specs_in_args(cat.args)) else name = cat.name if not name then internal_error("Missing .name in " .. (is_umbrella and "umbrella " or "") .. "'" .. table_type .. "' table for '" .. self._info.label .. "' category entry in module '" .. (self._data.module or "unknown") .. "'") elseif type(name) == "string" then -- otherwise, assume it's a category object and use it directly name = self:substitute_template_specs(name) if name:find("^Category:") then -- It's a non-poscatboiler category name. sortkey = sortkey or is_children and name:gsub("^Category:", "") or self:getCategoryName() else -- It's a label. sortkey = sortkey or is_children and name or self._info.label name = self:make_new{ label = name, code = lang, sc = sc, raw = raw, args = self:substitute_template_specs_in_args(cat.args) } end end end sortkey = sortkey or is_children and " " or self._info.label ret[i] = { name = name, description = is_children and self:substitute_template_specs(cat.description) or nil, sort = self:new_sortkey(sortkey) } end return ret end function Category:getParents() local is_umbrella, ret = not self._lang and not self._info.raw if self._sc then local parent1 = self:make_new{code = self._info.code, label = "terms in " .. self._sc:getCanonicalName() .. " script"} local parent2 = self:make_new{code = self._info.code, label = self._info.label, raw = self._info.raw, args = self._info.args} ret = { {name = parent1, sort = self._sc:getCanonicalName()}, {name = parent2, sort = self._sc:getCanonicalName()}, } else local parents, fallback_sort_base if is_umbrella then parents = self._data.umbrella and self._data.umbrella.parents or self._data.umbrella_parents fallback_sort_base = self._data.umbrella and self._data.umbrella.breadcrumb_and_first_sort_base or nil else parents = self._data.parents fallback_sort_base = self._data.breadcrumb_and_first_sort_base end ret = self:canonicalize_parents_children(parents, nil, fallback_sort_base) if not ret then return nil end end local self_cat = self:getCategoryName() for _, parent in ipairs(ret) do local parent_cat = parent.name.getCategoryName and parent.name:getCategoryName() if self_cat == parent_cat then internal_error(("Infinite loop would occur, as parent category '%s' is the same as the child category"):format(self_cat)) end end return ret end function Category:getChildren() local is_umbrella = not self._lang and not self._info.raw local children = self._data.children local ret = {} if not is_umbrella and children then for _, child in ipairs(children) do child = mw.clone(child) if type(child) ~= "table" then child = {name = child} end if not child.sort then child.sort = child.name end -- FIXME, is preserving the script correct? child.name = self:make_new{code = self._info.code, label = child.name, raw = child.raw, sc = self._info.sc} insert(ret, child) end end local extra_children if is_umbrella then extra_children = self._data.umbrella and self._data.umbrella.extra_children else extra_children = self._data.extra_children end extra_children = self:canonicalize_parents_children(extra_children, "children") if extra_children then for _, child in ipairs(extra_children) do insert(ret, child) end end return #ret > 0 and ret or nil end function Category:getUmbrella() local umbrella = self._data.umbrella if umbrella == false or self._info.raw or not self._lang or self._sc then return nil end -- If `umbrella` is a string, use that; otherwise, use the label. return self:make_new({label = type(umbrella) == "string" and umbrella or self._info.label}) end function Category:getAppendix() -- FIXME, this should be customizable. local lang, label = self._lang, self._info.label if self._info.raw or not (lang and label) then return nil end local appendix = make_title(100, lang:getCanonicalName() .. " " .. label) return appendix.exists and appendix.fullText or nil end function Category:getCatfixInfo() if self._lang or self._sc or self._info.raw then local langcode, sccode, lang, sc = self._data.catfix, self._data.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) elseif langcode == nil then -- not false lang = self._lang end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) elseif sccode == nil then -- not false sc = self._sc end return lang, sc elseif not self._data.umbrella then return end -- umbrella local langcode, sccode, lang, sc = self._data.umbrella.catfix, self._data.umbrella.catfix_sc if langcode then langcode = self:substitute_template_specs(langcode) lang = get_lang(langcode) end if sccode then sccode = self:substitute_template_specs(sccode) sc = get_script(sccode) end return lang, sc end function Category:getTOCTemplateName() -- This should only be invoked if getTOC() returns true, meaning to do the default algorithm, but getTOC() -- implements its own default algorithm. internal_error("This should never get called") end local export = {} function export.main(info) local self = setmetatable({_info = info}, Category) self:initCommon() return self._data and self or nil end export.new = Category.new return export o45t2ki3sumefh0zo037mj8zxk50lem cumhuriyet 0 1108 36949 25712 2026-08-18T03:35:32Z Ghybu 12 36949 wikitext text/x-wiki == تورکی == === وشەڕەتناسی === {{واڵا}} ===ناو === {{head|tr|ناو}} # [[کۆمار]] efr8q1s3ma1cu9yb38h8i1uo64bk2l6 خۆر 0 5025 36952 31204 2026-08-18T03:51:39Z Ghybu 12 36952 wikitext text/x-wiki == کوردیی ناوەندی == [[پەڕگە:The Sun by the Atmospheric Imaging Assembly of NASA's Solar Dynamics Observatory - 20100819.jpg|thumb|200x200px|خۆر]] === وشەڕەتناسی === {{واڵا}} ==== ناو ==== {{ckb-noun}} * ئەو [[ئەستێرە]]یەیە کە لە ناوەندی [[کۆمەڵەی خۆر]]دایە، و نزیکترین ئەستێرەیە لە [[زەوی]]یەوە. لە [[ئەستێرەناسی]] و ئەستێرەژمێریدا ھێمای [[☉]]ی بۆ دانراوە. # ڕۆژێکە کە جیھان ڕووناک دەکاتەوە ھەتاو.<ref name=":0">فەرھەنگی خاڵ</ref> # پیتێکە بەھەر ناوێکەوە نرا دەیکا بە «اسمی فاعل» [[نانخۆر]] ، [[گۆشتخۆر]] ، [[پیاوخۆر]].<ref name=":0" /> # ڕۆژی ئاسمان.<ref name=":1">ھەنبانە بۆرینە</ref> # پاشگر بەواتا: ئەوی دەخوا نانخۆر.<ref name=":1" /> # خۆر: خاک، گڵ، خۆڵ<ref name=":1" /><ref>فەرهەنگی شێخانی</ref> ==== ھاوواتاکان ==== * [[ھەتاو]]<ref name=":0" /> * [[ھۆر]]<ref name=":0" /><ref name=":1" /> * [[ڕۆژ]] * [[ڕۆ]]<ref name=":1" /> ==== وەرگێڕانەکان ==== {{وەرگێڕان-سەر|خۆر}} * عەرەبی: {{t|ar|الشمس}} * فارسی: {{t|fa|خورشید}} * ئیتالی: {{t|it|Sole}} * ئەڵمانی: {{t|de|Sonne}} * ئیسپانی: {{t|es|Sol}} {{trans-mid}} * ئینگلیزی: {{t|en|Sun}} * کورمانجی: {{t|kmr|Roj}} * تورکی: {{t|tr|Güneş}} * ھۆلەندی: {{t|nl|Zon}} * فەڕەنسی: {{t|fr|Soleil}} * سوێدی: {{t|sv|Solen}} {{وەرگێڕان-بن}} ====سەرچاوەکان==== <references /> [[پۆل:وشە سێ پیتییە کوردییەکان]] if9prmzxexy2h5y7biw0qy3pqzaes4t 36953 36952 2026-08-18T03:52:49Z Ghybu 12 /* کوردیی ناوەندی */ 36953 wikitext text/x-wiki == کوردیی ناوەندی == [[پەڕگە:The Sun by the Atmospheric Imaging Assembly of NASA's Solar Dynamics Observatory - 20100819.jpg|thumb|200x200px|خۆر]] === وشەڕەتناسی === {{واڵا}} === ناو === {{ckb-noun}} * ئەو [[ئەستێرە]]یەیە کە لە ناوەندی [[کۆمەڵەی خۆر]]دایە، و نزیکترین ئەستێرەیە لە [[زەوی]]یەوە. لە [[ئەستێرەناسی]] و ئەستێرەژمێریدا ھێمای [[☉]]ی بۆ دانراوە. # ڕۆژێکە کە جیھان ڕووناک دەکاتەوە ھەتاو.<ref name=":0">فەرھەنگی خاڵ</ref> # پیتێکە بەھەر ناوێکەوە نرا دەیکا بە «اسمی فاعل» [[نانخۆر]] ، [[گۆشتخۆر]] ، [[پیاوخۆر]].<ref name=":0" /> # ڕۆژی ئاسمان.<ref name=":1">ھەنبانە بۆرینە</ref> # پاشگر بەواتا: ئەوی دەخوا نانخۆر.<ref name=":1" /> # خۆر: خاک، گڵ، خۆڵ<ref name=":1" /><ref>فەرهەنگی شێخانی</ref> ==== ھاوواتاکان ==== * [[ھەتاو]]<ref name=":0" /> * [[ھۆر]]<ref name=":0" /><ref name=":1" /> * [[ڕۆژ]] * [[ڕۆ]]<ref name=":1" /> ==== وەرگێڕانەکان ==== {{وەرگێڕان-سەر|خۆر}} * عەرەبی: {{t|ar|الشمس}} * فارسی: {{t|fa|خورشید}} * ئیتالی: {{t|it|Sole}} * ئەڵمانی: {{t|de|Sonne}} * ئیسپانی: {{t|es|Sol}} {{trans-mid}} * ئینگلیزی: {{t|en|Sun}} * کورمانجی: {{t|kmr|Roj}} * تورکی: {{t|tr|Güneş}} * ھۆلەندی: {{t|nl|Zon}} * فەڕەنسی: {{t|fr|Soleil}} * سوێدی: {{t|sv|Solen}} {{وەرگێڕان-بن}} ====سەرچاوەکان==== <references /> [[پۆل:وشە سێ پیتییە کوردییەکان]] poic2iesebdhseb7y8h4wywc2nhdggw kirin 0 7347 36917 36669 2026-08-17T22:25:13Z Ghybu 12 /* کرمانجی */ test 36917 wikitext text/x-wiki == کرمانجی == === گۆکردن === * {{kmr-IPA}} * {{دەنگ|kmr|LL-Q36163 (kmr)-Key Mîrza-kirin.wav}} === کارر === === کار === {{kmr-verb}} # [[کردن]] === ناو === {{kmr-noun|f}} # [[کار]], [[کردەوە]] 23plqwve7nua3znxkmsjqa3j2uvriwg 36918 36917 2026-08-17T22:27:04Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36917|36917]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36918 wikitext text/x-wiki == کرمانجی == === گۆکردن === * {{kmr-IPA}} * {{دەنگ|kmr|LL-Q36163 (kmr)-Key Mîrza-kirin.wav}} === کار === {{kmr-verb}} # [[کردن]] === ناو === {{kmr-noun|f}} # [[کار]], [[کردەوە]] aq7hb2bt3dtbtrl9vu7pcxnn92062qn لۆری 0 8257 36950 32914 2026-08-18T03:37:52Z Ghybu 12 36950 wikitext text/x-wiki == کوردیی ناوەندی == ===وشەڕەتناسی === {{واڵا}} === ناو === {{ckb-noun}} # ناوی ئۆتۆمۆبیلێکی زەبەلاحە کە کاری ڕاکێشان و شتی تری پێ دەکرێت ==== وەرگێڕانەکان ==== {{وەرگێڕان-سەر|}} {{وەرگێڕان-بن}} je9vxbiedc6itekhgqeu6ufzi2njn0j مۆدیوول:category tree/lemmas 828 9311 36947 36849 2026-08-18T02:23:00Z Ghybu 12 36947 Scribunto text/plain local labels = {} local raw_categories = {} local handlers = {} ----------------------------------------------------------------------------- -- -- -- LABELS -- -- -- ----------------------------------------------------------------------------- local diminutive_augmentative_poses = { "adjectives", "adverbs", "interjections", "nouns", "numerals", "prefixes", "proper nouns", "pronouns", "suffixes", "verbs" } labels["لێماکان"] = { description = "{{{langname}}} [[Wiktionary:Lemmas|lemmas]], categorized by their part of speech.", umbrella_parents = "Fundamental", parents = {{name = "{{{langcat}}}", raw = true, sort = " "}}, } labels["abstract verbs"] = { description = "{{{langname}}} abstract verbs of motion whose motion is multidirectional (as opposed to unidirectional) or indirect, or whose action is repeated or in a series, instead of being a single, completed action. Abstract verbs are always imperfective in aspect, even with prefixes that are normally associated with the perfective aspect.", additional = "See also [[abstract verb]].", parents = {"کارەکان"}, } labels["action nouns"] = { description = "{{{langname}}} nouns denoting action of a verb or verbal root that it is derived from.", parents = {"ناوەکان"}, } labels["act-related adverbs"] = { description = "{{{langname}}} adverbs that indicate the motive or other background information for an action.", parents = {"adverbs"}, } labels["active verbs"] = { description = "{{{langname}}} verbs that indicate an activity", parents = {"کارەکان"}, } labels["adjective concords"] = { description = "{{{langname}}} concords that are prefixed to adjective stems.", parents = {"concords"}, } labels["ھاوەڵناوەکان"] = { description = "{{{langname}}} terms that give attributes to nouns, extending their definitions.", parents = {"لێماکان"}, } labels["adverbial accusatives"] = { description = "Accusative case-forms in {{{langname}}} used as adverbs.", parents = {"adverbs"}, } labels["adverbs"] = { description = "{{{langname}}} terms that modify clauses, sentences and phrases directly.", parents = {"لێماکان"}, } labels["affixes"] = { description = "Morphemes attached to existing {{{langname}}} words.", parents = {"morphemes"}, } labels["agent nouns"] = { description = "{{{langname}}} nouns that denote an agent that performs the action denoted by the verb from which the noun is derived.", parents = {"ناوەکان"}, } labels["ambipositions"] = { description = "{{{langname}}} adpositions that can occur either before or after their objects.", parents = {"لێماکان"}, } labels["ambitransitive verbs"] = { description = "{{{langname}}} verbs that may or may not direct actions, occurrences or states to grammatical objects.", parents = {"verbs", "transitive verbs", "intransitive verbs"}, } labels["animal commands"] = { description = "{{{langname}}} words used to communicate with animals.", parents = {"interjections"}, } labels["articles"] = { description = "{{{langname}}} terms that indicate and specify nouns.", parents = {"determiners"}, } labels["aspect adverbs"] = { description = "{{{langname}}} adverbs that express [[w:Grammatical aspect|grammatical aspect]], describing the flow of time in relation to a statement.", parents = {"adverbs"}, } for _, pos in ipairs(diminutive_augmentative_poses) do labels["augmentative " .. pos] = { description = "{{{langname}}} " .. pos .. " that are derived from a base word to convey big size or big intensity.", parents = {pos}, } end labels["attenuative verbs"] = { description = "{{{langname}}} verbs that indicate that an action or event is performed or takes place gently, lightly, partially, perfunctorily or to an otherwise reduced extent.", parents = {"کارەکان"}, } labels["autobenefactive verbs"] = { description = "{{{langname}}} verbs that indicate that the agent of an action is also its benefactor.", parents = {"کارەکان"}, } labels["automative verbs"] = { description = "{{{langname}}} verbs that indicate actions directed at or a change of state of the grammatical subject.", parents = {"کارەکان"}, } labels["auxiliary verbs"] = { description = "{{{langname}}} verbs that provide additional conjugations for other verbs.", parents = {"کارەکان"}, } labels["biaspectual verbs"] = { description = "{{{langname}}} verbs that can be both imperfective and perfective.", parents = {"کارەکان"}, } labels["causative verbs"] = { description = "{{{langname}}} verbs that express causing actions or states rather than performing or being them directly. Use this only for separate verbs (as opposed to causative forms that are part of the inflection of verbs).", parents = {"کارەکان"}, } labels["circumfixes"] = { description = "Affixes attached to both the beginning and the end of {{{langname}}} words, functioning together as single units.", parents = {"morphemes"}, } labels["circumpositions"] = { description = "{{{langname}}} adpositions that appear on both sides of their objects.", parents = {"لێماکان"}, } labels["classifiers"] = { description = "{{{langname}}} terms that classify nouns according to their meanings.", parents = {"لێماکان"}, } labels["clitics"] = { description = "{{{langname}}} morphemes that function as independent words, but are always attached to another word.", parents = {"morphemes"}, } for _, pos in ipairs { "nouns", "suffixes" } do labels["collective " .. pos] = { description = "{{{langname}}} " .. pos .. " that indicate groups of related things or beings, without the need of grammatical pluralization.", parents = {pos}, } end labels["combining forms"] = { description = "Forms of {{{langname}}} words that do not occur independently, but are used when joined with other words.", parents = {"morphemes"}, } labels["comparable adjectives"] = { description = "{{{langname}}} adjectives that can be inflected to display different degrees of comparison.", parents = {"ھاوەڵناوەکان"}, } labels["comparable adverbs"] = { description = "{{{langname}}} adverbs that can be inflected to display different degrees of comparison.", parents = {"adverbs"}, } labels["comparative-only adjectives"] = { description = "{{{langname}}} adjectives that are only used in their comparative forms.", parents = {"ھاوەڵناوەکان"}, } labels["completive verbs"] = { description = "{{{langname}}} verbs which refer to the completion of an action which has already commenced or which has already been performed upon a subset of the entities which it affects.", parents = {"کارەکان"}, } labels["concords"] = { description = "{{{langname}}} prefixes attached to words to show agreement with a noun or pronoun.", parents = {"prefixes"}, } labels["concrete verbs"] = { description = "{{{langname}}} concrete verbs refer to a verbal aspect in verbs of motion that is unidirectional (as opposed to multidirectional), a definitely directed motion, or a single, completed action (instead of a repeated action or series of actions). Concrete verbs may be either imperfective or perfective.", additional = "See also [[concrete verb]].", parents = {"کارەکان"}, } labels["conjunctions"] = { description = "{{{langname}}} terms that connect words, phrases or clauses together.", parents = {"لێماکان"}, } labels["conjunctive adverbs"] = { description = "{{{langname}}} adverbs that connect two independent clauses together.", parents = {"adverbs"}, } labels["continuative verbs"] = { description = "{{{langname}}} verbs that express continuing action.", parents = {"کارەکان"}, } labels["control verbs"] = { description = "{{{langname}}} verbs that take multiple arguments, one of which is another verb. One of the control verb's arguments is syntactically both an argument of the control verb and an argument of the other verb.", parents = {"کارەکان"}, } labels["cooperative verbs"] = { description = "{{{langname}}} verbs that indicate cooperation", parents = {"کارەکان"}, } labels["coordinating conjunctions"] = { description = "{{{langname}}} conjunctions that indicate equal syntactic importance between connected items.", parents = {"conjunctions"}, } labels["copulative verbs"] = { description = "{{{langname}}} verbs that may take adjectives as their complement.", parents = {"کارەکان"}, } labels["ناوە ژماردەنییەکان"] = { description = "ناوە ژماردەنییە {{{langname}}}یەکان کە دەتوانرێت ڕاستەوخۆ بە ژمارەیی بپێورێت.", parents = {"ناوەکان"}, } labels["ناوە تایبەتەکان"] = { description = "ناوە تایبەتە {{{langname}}}یەکان کە دەتوانرێت ڕاستەوخۆ بە ژمارەیی بپێورێت.", parents = {"ناوەکان"}, } labels["countable numerals"] = { description = "{{{langname}}} numerals that can be quantified directly by other numerals.", parents = {"numerals"}, } labels["countable suffixes"] = { description = "{{{langname}}} suffixes that can be used to form nouns that can be quantified directly by numerals.", parents = {"numerals"}, } labels["counters"] = { description = "{{{langname}}} terms that combine with numerals to express quantity of nouns.", parents = {"لێماکان"}, } labels["cumulative verbs"] = { description = "{{{langname}}} verbs which indicate that an action or event gradually yields a certain or significant quantity or effect.", parents = {"کارەکان"}, } labels["degree adverbs"] = { description = "{{{langname}}} adverbs that express a particular degree to which the word they modify applies.", parents = {"adverbs"}, } labels["delimitative verbs"] = { description = "{{{langname}}} verbs which indicate that an action or event is performed or takes place briefly or to an otherwise reduced extent.", parents = {"کارەکان"}, } labels["demonstrative adjectives"] = { description = "{{{langname}}} adjectives that refer to nouns, comparing them to external references.", parents = {"adjectives", {name = "demonstrative pro-forms", sort = "adjectives"}}, } labels["demonstrative adverbs"] = { description = "{{{langname}}} adverbs that refer to other adverbs, comparing them to external references.", parents = {"adverbs", {name = "demonstrative pro-forms", sort = "adverbs"}}, } labels["denominal verbs"] = { -- in [[Appendix:Glossary]]; "denominative" more frequent? description = "{{{langname}}} verbs that derive from nouns.", parents = { "verbs" }, } labels["demonstrative determiners"] = { description = "{{{langname}}} determiners that refer to nouns, comparing them to external references.", parents = {"determiners", {name = "demonstrative pro-forms", sort = "determiners"}}, } labels["demonstrative pronouns"] = { description = "{{{langname}}} pronouns that refer to nouns, comparing them to external references.", parents = {"pronouns", {name = "demonstrative pro-forms", sort = "pronouns"}}, } labels["deponent verbs"] = { description = "{{{langname}}} verbs that have active meanings but are not conjugated in the active voice.", parents = {"کارەکان"}, } labels["derivational prefixes"] = { description = "{{{langname}}} prefixes that are used to create new words.", parents = {"prefixes"}, } labels["derivational suffixes"] = { description = "{{{langname}}} suffixes that are used to create new words.", parents = {"suffixes"}, } labels["derivative verbs"] = { description = "{{{langname}}} verbs that are derived from nouns and adjectives.", parents = {"کارەکان"}, } labels["desiderative verbs"] = { description = "{{{langname}}} verbs with the following morphology: verbal root xxx + [[desiderative]] affix, and the following semantics: to wish to do the action xxx.", parents = {"کارەکان"}, } labels["determinatives"] = { description = "{{{langname}}} terms that indicate the general class to which the following logogram belongs.", parents = {"لێماکان"}, } labels["determiners"] = { description = "{{{langname}}} terms that narrow down, within the conversational context, the referent of the following noun.", parents = {"لێماکان"}, } labels["diminutiva tantum"] = { description = "{{{langname}}} nouns or noun senses that are mostly or exclusively used in the diminutive form.", parents = {"ناوەکان"}, } for _, pos in ipairs(diminutive_augmentative_poses) do labels["diminutive " .. pos] = { description = "{{{langname}}} " .. pos .. " that are derived from a base word to convey endearment, small size or small intensity.", parents = {pos}, } end labels["discourse particles"] = { description = "{{{langname}}} particles that manage the flow and structure of discourse.", parents = {"particles"}, } labels["distributive verbs"] = { description = "{{{langname}}} verbs which indicate that an action or event involves multiple participants or a large quantity of an uncountable mass, usually as the grammatical subject in the case of intransitive verbs and as the grammatical object in the case of transitive verbs.", parents = {"کارەکان"}, } labels["ditransitive verbs"] = { description = "{{{langname}}} verbs that indicate actions, occurrences or states of two grammatical objects simultaneously, one direct and one indirect.", parents = {"verbs", "transitive verbs"}, } labels["dualia tantum"] = { description = "{{{langname}}} nouns that are mostly or exclusively used in the dual form.", parents = {"ناوەکان"}, } labels["duration adverbs"] = { description = "{{{langname}}} adverbs that express duration in time.", parents = {"time adverbs"}, } labels["ergative verbs"] = { description = "{{{langname}}} [[Appendix:Glossary#ergative|ergative verb]]s: intransitive verbs that become causatives when used transitively.", parents = {"verbs", "intransitive verbs", "transitive verbs"}, } labels["excessive verbs"] = { description = "{{{langname}}} verbs that indicate that an action is performed to an excessive extent.", parents = {"کارەکان"}, } labels["enclitics"] = { description = "{{{langname}}} clitics that attach to the preceding word.", parents = {"clitics"}, } labels["nouns with other-gender equivalents"] = { description = "{{{langname}}} nouns that refer to gendered concepts (e.g. [[actor]] vs. [[actress]], [[king]] vs. [[queen]]) and have corresponding other-gender equivalent terms.", parents = {"ناوەکان"}, } labels["female equivalent nouns"] = { description = "{{{langname}}} nouns that refer to female beings with the same characteristics as the base noun.", parents = {"nouns with other-gender equivalents"}, } labels["neuter equivalent nouns"] = { description = "{{{langname}}} nouns that refer to neuter beings with the same characteristics as the base noun.", parents = {"nouns with other-gender equivalents"}, } labels["female equivalent suffixes"] = { description = "{{{langname}}} suffixes that refer to female beings with the same characteristics as the base suffix.", parents = {"noun-forming suffixes"}, } labels["focus adverbs"] = { description = "{{{langname}}} adverbs that indicate [[w:Focus (linguistics)|focus]] within the sentence.", parents = {"adverbs"}, } labels["frequency adverbs"] = { description = "{{{langname}}} adverbs that express repetition with a certain frequency or interval.", parents = {"time adverbs"}, } labels["frequentative verbs"] = { description = "{{{langname}}} verbs that express repeated action.", parents = {"کارەکان"}, } labels["general pronouns"] = { description = "{{{langname}}} pronouns that refer to all persons, things, abstract ideas and their characteristics.", parents = {"pronouns"}, } labels["generational moieties"] = { description = "{{{langname}}} moieties that alternate every generation.", parents = {"moieties"}, } labels["ideophones"] = { description = "{{{langname}}} terms that evoke an idea, especially a sensation or impression, with a sound.", parents = {"لێماکان"}, } labels["imperfective verbs"] = { description = "{{{langname}}} verbs that express actions considered as ongoing or continuous, as opposed to completed events.", parents = {"کارەکان"}, } labels["impersonal verbs"] = { description = "{{{langname}}} verbs that do not indicate actions, occurrences or states of any specific grammatical subject.", parents = {"کارەکان"}, } labels["inchoative verbs"] = { description = "{{{langname}}} verbs that indicate the beginning of an action or event.", parents = {"کارەکان"}, } labels["indefinite adjectives"] = { description = "{{{langname}}} adjectives that refer to unspecified adjective meanings.", parents = {"adjectives", {name = "indefinite pro-forms", sort = "adjectives"}}, } labels["indefinite adverbs"] = { description = "{{{langname}}} adverbs that refer to unspecified adverbial meanings.", parents = {"adverbs", {name = "indefinite pro-forms", sort = "adverbs"}}, } labels["indefinite determiners"] = { description = "{{{langname}}} determiners that designate an unidentified noun.", parents = {"determiners", {name = "indefinite pro-forms", sort = "determiners"}}, } labels["indefinite pronouns"] = { description = "{{{langname}}} pronouns that refer to unspecified nouns.", parents = {"pronouns", {name = "indefinite pro-forms", sort = "pronouns"}}, } labels["infixes"] = { description = "Affixes inserted inside {{{langname}}} words.", parents = {"morphemes"}, } labels["inflectional prefixes"] = { description = "{{{langname}}} prefixes that are used as inflectional beginnings in noun, adjective or verb paradigms.", parents = {"prefixes"}, } labels["inflectional suffixes"] = { description = "{{{langname}}} suffixes that are used as inflectional endings in noun, adjective or verb paradigms.", parents = {"suffixes"}, } labels["intensive verbs"] = { description = "{{{langname}}} verbs which indicate that an action is performed vigorously, enthusiastically, forcefully or to an otherwise enlarged extent.", parents = {"کارەکان"}, } labels["interfixes"] = { description = "Affixes used to join two {{{langname}}} words or morphemes together.", parents = {"morphemes"}, } labels["interjections"] = { description = "{{{langname}}} terms that express emotions, sounds, etc. as exclamations.", parents = {"لێماکان"}, } labels["interrogative adjectives"] = { description = "{{{langname}}} adjectives that indicate questions.", parents = {"adjectives", {name = "interrogative pro-forms", sort = "adjectives"}}, } labels["interrogative adverbs"] = { description = "{{{langname}}} adverbs that indicate questions.", parents = {"adverbs", {name = "interrogative pro-forms", sort = "adverbs"}}, } labels["interrogative determiners"] = { description = "{{{langname}}} determiners that indicate questions.", parents = {"determiners", {name = "interrogative pro-forms", sort = "determiners"}}, } labels["interrogative particles"] = { description = "{{{langname}}} particles that indicate questions.", parents = {"particles", {name = "interrogative pro-forms", sort = "particles"}}, } labels["interrogative pronouns"] = { description = "{{{langname}}} pronouns that indicate questions.", parents = {"pronouns", {name = "interrogative pro-forms", sort = "pronouns"}}, } labels["intransitive verbs"] = { description = "{{{langname}}} verbs that don't require any grammatical objects.", parents = {"کارەکان"}, } labels["iterative verbs"] = { description = "{{{langname}}} verbs that express the repetition of an event.", parents = {"کارەکان"}, } labels["location adverbs"] = { description = "{{{langname}}} adverbs that indicate location.", parents = {"adverbs"}, } labels["male equivalent nouns"] = { description = "{{{langname}}} nouns that refer to male beings with the same characteristics as the base noun.", parents = {"nouns with other-gender equivalents"}, } labels["manner adverbs"] = { description = "{{{langname}}} adverbs that indicate the manner, way or style in which an action is performed.", parents = {"adverbs"}, } labels["modal adverbs"] = { description = "{{{langname}}} adverbs that express [[w:Linguistic modality|linguistic modality]], indicating the mood or attitude of the speaker with respect to what is being said.", parents = {"sentence adverbs"}, } labels["modal particles"] = { description = "{{{langname}}} particles that reflect the mood or attitude of the speaker, without changing the basic meaning of the sentence.", parents = {"particles"}, } labels["modal verbs"] = { description = "{{{langname}}} verbs that indicate [[grammatical mood]].", parents = {"auxiliary verbs"}, } labels["moieties"] = { description = "{{{langname}}} pairs of abstract categories separating people and the environment.", parents = {"لێماکان"}, } labels["momentane verbs"] = { description = "{{{langname}}} verbs that express a sudden and brief action.", parents = {"کارەکان"}, } labels["morphemes"] = { description = "{{{langname}}} word-elements used to form full words.", parents = {"لێماکان"}, } labels["multiword terms"] = { description = "{{{langname}}} lemmas that are an [[WT:CFI#Idiomaticity|idiomatic]] combination of multiple words.", parents = {"لێماکان"}, } labels["negative verbs"] = { description = "{{{langname}}} verbs that indicate the lack of an action.", parents = {"کارەکان"}, } labels["negative particles"] = { description = "{{{langname}}} particles that indicate negation.", parents = {"particles"}, } labels["negative pronouns"] = { description = "{{{langname}}} pronouns that refer to negative or non-existent references.", parents = {"pronouns"}, } labels["neutral verbs"] = { description = "{{{langname}}} verbs that indicate either or both an activity or a result of an activity", parents = {"کارەکان"}, } labels["nominalized adjectives"] = { description = "{{{langname}}} adjectives that are used as nouns.", parents = {"nouns", "adjectives"}, } labels["non-constituents"] = { description = "{{{langname}}} terms that are not grammatical [[constituent#Noun|constituents]], and therefore need to be combined with additional terms to form a complete phrase.", parents = {"phrases"}, } labels["noun prefixes"] = { description = "{{{langname}}} prefixes attached to a noun that display its noun class.", parents = {"prefixes"}, } labels["ناوەکان"] = { description = "{{{langname}}} terms that indicate people, beings, things, places, phenomena, qualities or ideas.", parents = {"لێماکان"}, } labels["nouns by classifier"] = { description = "{{{langname}}} nouns organized by the classifier they are used with.", parents = {{name = "nouns", sort = "classifier"}}, } labels["numerals"] = { description = "{{{langname}}} terms that quantify nouns.", parents = {"لێماکان"}, } labels["object concords"] = { description = "{{{langname}}} concords used to show the grammatical object.", parents = {"concords"}, } labels["object pronouns"] = { description = "{{{langname}}} pronouns that refer to grammatical objects.", parents = {"pronouns"}, } labels["particles"] = { description = "{{{langname}}} terms that do not belong to any of the inflected grammatical word classes, often lacking their own grammatical functions and forming other parts of speech or expressing the relationship between clauses.", parents = {"لێماکان"}, } labels["passive verbs"] = { description = "{{{langname}}} verbs that are usually used in passive voice.", parents = {"کارەکان"}, } labels["perfective verbs"] = { description = "{{{langname}}} verbs that express actions considered as completed events, as opposed to ongoing or continuous.", parents = {"کارەکان"}, } labels["personal pronouns"] = { description = "{{{langname}}} pronouns that are used as substitutes for known nouns.", parents = {"pronouns"}, } labels["phrasal verbs"] = { description = "{{{langname}}} verbs accompanied by particles, such as prepositions and adverbs.", parents = {"verbs", "phrases"}, } labels["phrasal prepositions"] = { description = "{{{langname}}} prepositions formed with combinations of other terms.", parents = {"prepositions", "phrases"}, } labels["pluralia tantum"] = { description = "{{{langname}}} nouns that are mostly or exclusively used in the plural form.", parents = {"ناوەکان"}, } labels["point-in-time adverbs"] = { description = "{{{langname}}} adverbs that reference a specific point in time, e.g. {{m|en|yesterday}}, {{m+|es|anoche||last night}} or {{m+|hu|egykor||at one o'clock}}.", parents = {"time adverbs"}, } labels["possessable nouns"] = { description = "{{{langname}}} nouns can have their possession indicated directly by possessive pronouns.", parents = {"ناوەکان"}, umbrella = { description = "Categories with nouns that can have their possession indicated directly by possessive pronouns and, in some languages, be transformed into adjectives.", parents = {"Lemmas subcategories by language"}, breadcrumb = "Possessable nouns by language", }, } labels["possessional adjectives"] = { description = "{{{langname}}} adjectives that indicate that a noun is in possession of something.", parents = {"ھاوەڵناوەکان"}, } labels["possessive adjectives"] = { description = "{{{langname}}} adjectives that indicate ownership.", parents = {"ھاوەڵناوەکان"}, } labels["possessive concords"] = { description = "{{{langname}}} concords used to show possession.", parents = {"concords"}, } labels["possessive determiners"] = { description = "{{{langname}}} determiners that indicate ownership.", parents = {"determiners"}, } labels["possessive pronouns"] = { description = "{{{langname}}} pronouns that indicate ownership.", parents = {"pronouns"}, } labels["postpositional phrases"] = { description = "{{{langname}}} phrases headed by a postposition.", parents = {"phrases", "postpositions"}, } labels["postpositions"] = { description = "{{{langname}}} adpositions that are placed after their objects.", parents = {"لێماکان"}, } labels["predicatives"] = { description = "{{{langname}}} elements of the predicate that supplement the subject or object of a sentence via the verb.", parents = {"لێماکان"}, } labels["prefixes"] = { description = "Affixes attached to the beginning of {{{langname}}} words.", parents = {"morphemes"}, } labels["prepositional phrases"] = { description = "{{{langname}}} phrases headed by a preposition.", parents = {"phrases", "prepositions"}, } labels["prepositions"] = { description = "{{{langname}}} adpositions that are placed before their objects.", parents = {"لێماکان"}, } labels["ablative prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the ablative case.", parents = {"prepositions"}, } labels["accusative prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the accusative case.", parents = {"prepositions"}, } labels["dative prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the dative case.", parents = {"prepositions"}, } labels["genitive prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the genitive case.", parents = {"prepositions"}, } labels["instrumental prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the instrumental case.", parents = {"prepositions"}, } labels["matrilineal moieties"] = { description = "{{{langname}}} moieties inherited from an individual's mother.", parents = {"moieties"}, } labels["nominative prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the nominative case.", parents = {"prepositions"}, } labels["patrilineal moieties"] = { description = "{{{langname}}} moieties inherited from an individual's father.", parents = {"moieties"}, } labels["pejorative suffixes"] = { description = "{{{langname}}} suffixes that [[belittle]] (lessen in value).", parents = {"suffixes"}, } labels["prepositional prepositions"] = { description = "{{{langname}}} prepositions that cause the succeeding noun to be in the prepositional case.", parents = {"prepositions"}, } labels["prenouns"] = { description = "{{{langname}}} prefixes of various kinds that are attached to nouns.", parents = {"prefixes"}, } labels["preverbs"] = { description = "{{{langname}}} prefixes of various kinds that are attached to verbs.", parents = {"prefixes"}, } labels["privative verbs"] = { description = "{{{langname}}} verbs that indicate that the grammatical object is deprived of something or that something is removed from the object.", parents = {"کارەکان"}, } labels["pronominal adverbs"] = { description = "{{{langname}}} adverbs that are formed by combining a pronoun with a preposition.", parents = {"adverbs", "prepositions", "pronouns"}, } labels["pronominal concords"] = { description = "{{{langname}}} concords that are prefixed to pronominal stems.", parents = {"concords"}, } labels["pronouns"] = { description = "{{{langname}}} terms that refer to and substitute nouns.", parents = {"لێماکان"}, } labels["proper nouns"] = { description = "{{{langname}}} nouns that indicate individual entities, such as names of persons, places or organizations.", parents = {"ناوەکان"}, } labels["punctual adverbs"] = { description = "{{{langname}}} adverbs that express a single point or span in time.", parents = {"time adverbs"}, } labels["raising verbs"] = { description = "{{{langname}}} verbs that, in a matrix or main clause, take an argument from an embedded or subordinate clause; in other words, a raising verb appears with a syntactic argument that is not its semantic argument, but is rather the semantic argument of an embedded predicate.", parents = {"کارەکان"}, } labels["reciprocal pronouns"] = { description = "{{{langname}}} pronouns that refer back to a plural subject and express an action done in two or more directions.", parents = {"pronouns", "personal pronouns"}, } labels["reciprocal verbs"] = { description = "{{{langname}}} verbs that indicate actions, occurrences or states directed from multiple subjects to each other.", parents = {"کارەکان"}, } labels["reflexive pronouns"] = { description = "{{{langname}}} pronouns that refer back to the subject.", parents = {"pronouns", "personal pronouns"}, } labels["reflexive verbs"] = { description = "{{{langname}}} verbs that indicate actions, occurrences or states directed from the grammatical subjects to themselves.", parents = {"کارەکان"}, } labels["relational adjectives"] = { description = "{{{langname}}} adjectives that stand in place of a noun when modifying another noun.", parents = {"ھاوەڵناوەکان"}, } labels["relational nouns"] = { description = "{{{langname}}} nouns used to indicate a relation between other two nouns by means of possession.", parents = {"ناوەکان"}, } labels["relative adjectives"] = { description = "{{{langname}}} adjectives used to indicate [[relative clause]]s.", parents = {"adjectives", {name = "relative pro-forms", sort = "adjectives"}}, } labels["relative adverbs"] = { description = "{{{langname}}} adverbs used to indicate [[relative clause]]s.", parents = {"adverbs", {name = "relative pro-forms", sort = "adverbs"}}, } labels["relative determiners"] = { description = "{{{langname}}} determiners used to indicate [[relative clause]]s.", parents = {"determiners", {name = "relative pro-forms", sort = "determiners"}}, } labels["relative concords"] = { description = "{{{langname}}} concords that are prefixed to relative stems.", parents = {"concords"}, } labels["relative pronouns"] = { description = "{{{langname}}} pronouns used to indicate [[relative clause]]s.", parents = {"pronouns", {name = "relative pro-forms", sort = "pronouns"}}, } labels["relatives"] = { description = "{{{langname}}} terms that give attributes to nouns, acting grammatically as relative clauses.", parents = {"لێماکان"}, } labels["repetitive verbs"] = { description = "{{{langname}}} verbs that indicate actions or events which are performed or occur again, anew or differently.", parents = {"کارەکان"}, } labels["resultative verbs"] = { description = "{{{langname}}} verbs that indicate a result of some action", parents = {"کارەکان"}, } labels["reversative verbs"] = { description = "{{{langname}}} verbs that indicate that the reversal or undoing of an action, event or state.", parents = {"کارەکان"}, } labels["saturative verbs"] = { description = "{{{langname}}} verbs which indicate that an action is performed to the point of saturation or satisfaction.", parents = {"کارەکان"}, } labels["semelfactive verbs"] = { description = "{{{langname}}} verbs that are punctual (instantaneous, momentive), perfective (treated as a unitary whole with no explicit internal temporal structure), and telic (having a boundary out of which the activity cannot be said to have taken place or continue).", parents = {"کارەکان"}, } labels["sentence adverbs"] = { description = "{{{langname}}} adverbs that modify an entire clause or sentence.", parents = {"adverbs"}, } labels["sequence adverbs"] = { description = "{{{langname}}} conjunctive adverbs that express sequence in space or time.", parents = {"conjunctive adverbs"}, } labels["simulfixes"] = { description = "Affixes replacing positions in {{{langname}}} words.", parents = {"morphemes"}, } labels["singulative nouns"] = { description = "{{{langname}}} nouns that indicate a single item of a group of related things or beings.", parents = {"ناوەکان"}, } labels["singularia tantum"] = { description = "{{{langname}}} nouns that are mostly or exclusively used in the singular form.", parents = {"ناوەکان"}, } labels["stative verbs"] = { description = "{{{langname}}} verbs that define a state with no or insignificant internal dynamics.", parents = {"کارەکان"}, } labels["stems"] = { description = "Morphemes from which {{{langname}}} words are formed.", parents = {"morphemes"}, } labels["subordinating conjunctions"] = { description = "{{{langname}}} conjunctions that indicate relations of syntactic dependence between connected items.", parents = {"conjunctions"}, } labels["subject concords"] = { description = "{{{langname}}} concords used to show the grammatical subject.", parents = {"concords"}, } labels["subject pronouns"] = { description = "{{{langname}}} pronouns that refer to grammatical subjects.", parents = {"pronouns"}, } labels["suffixes"] = { description = "Affixes attached to the end of {{{langname}}} words.", parents = {"morphemes"}, } labels["splitting verbs"] = { description = "{{{langname}}} bisyllabic verbs that obligatorily split around a direct object or pronoun.", parents = {"کارەکان"}, } labels["terminative verbs"] = { description = "{{{langname}}} verbs that indicate that an action or event ceases.", parents = {"کارەکان"}, } labels["time adverbs"] = { description = "{{{langname}}} adverbs that indicate time.", parents = {"adverbs"}, } labels["transfixes"] = { description = "Discontinuous affixes inserted within a word root.", parents = {"morphemes"}, } labels["transformative verbs"] = { description = "{{{langname}}} verbs that indicate a change of state or nature, in the subject for intransitive verbs and in the object for transitive verbs.", parents = {"کارەکان"}, } labels["transitive verbs"] = { description = "{{{langname}}} verbs that indicate actions, occurrences or states directed to one or more grammatical objects.", parents = {"کارەکان"}, } labels["uncomparable adjectives"] = { description = "{{{langname}}} adjectives that are not inflected to display different degrees of comparison.", parents = {"ھاوەڵناوەکان"}, } labels["uncomparable adverbs"] = { description = "{{{langname}}} adverbs that are not inflected to display different degrees of comparison.", parents = {"adverbs"}, } labels["ناوە ژماردەنییەکان"] = { description = "{{{langname}}} nouns that indicate qualities, ideas, unbounded mass or other abstract concepts that cannot be quantified directly by numerals.", parents = {"ناوەکان"}, } labels["uncountable numerals"] = { description = "{{{langname}}} numerals that cannot be quantified directly by other numerals.", parents = {"numerals"}, } labels["uncountable proper nouns"] = { description = "{{{langname}}} proper nouns that cannot be quantified directly by numerals.", parents = {"proper nouns"}, } labels["uncountable suffixes"] = { description = "{{{langname}}} suffixes that can be used to form nouns that cannot be quantified directly by numerals.", parents = {"numerals"}, } labels["unpossessable nouns"] = { description = "{{{langname}}} nouns that cannot have their possession indicated directly by possessive pronouns.", parents = {"ناوەکان"}, umbrella = { description = "Categories with nouns that cannot have their possession indicated directly by possessive pronouns or, in some languages, be transformed into adjectives.", parents = {"Lemmas subcategories by language"}, breadcrumb = "Unpossessable nouns by language", }, } labels["verbal nouns"] = { description = "{{{langname}}} nouns morphologically related to a verb and similar to it in meaning.", parents = {"ناوەکان"}, } labels["verbal adjectives"] = { description = "{{{langname}}} adjectives describing the condition or state resulting from the action of the corresponding verb.", parents = {"ھاوەڵناوەکان"}, } labels["کارەکان"] = { description = "{{{langname}}} terms that indicate actions, occurrences or states.", parents = {"لێماکان"}, } labels["verbs of movement"] = { description = "{{{langname}}} verbs that indicate physical movement of the grammatical subject across a trajectory, with a starting point and an endpoint.", parents = {"کارەکان"}, } -- Add "POS-forming suffixes". local poses_derived_by_suffix = { "adjective", "adverb", "noun", "verb", } for _, pos in pairs(poses_derived_by_suffix) do labels[pos .. "-forming suffixes"] = { description = "{{{langname}}} suffixes that are used to derive " .. pos .. "s from other words.", parents = {"derivational suffixes"}, } end local labels2 = {} -- Add "reconstructed" subcategories; add 'umbrella_parents' key if not -- already present. for key, data in pairs(labels) do labels2[key] = data if not data.umbrella_parents then data.umbrella_parents = "Lemmas subcategories by language" end labels2["reconstructed " .. key] = { description = "{{{langname}}} " .. key .. " that have been linguistically [[Wiktionary:Reconstructed terms|reconstructed]].", umbrella_parents = "Lemmas subcategories by language", parents = {key, {name = "reconstructed terms", sort = key}} } end ----------------------------------------------------------------------------- -- -- -- RAW CATEGORIES -- -- -- ----------------------------------------------------------------------------- raw_categories["Lemmas subcategories by language"] = { description = "Umbrella categories covering topics related to lemmas.", additional = "{{{umbrella_meta_msg}}}", parents = { "Umbrella metacategories", {name = "لێماکان", is_label = true, sort = " "}, }, } ----------------------------------------------------------------------------- -- -- -- HANDLERS -- -- -- ----------------------------------------------------------------------------- -- Handler for e.g. [[:Category:English phrasal verbs with particle (around)]]. table.insert(handlers, function(data) local particle = data.label:match("^phrasal verbs with particle %((.-)%)$") if particle then local tagged_text = require("Module:script utilities").tag_text(particle, data.lang, nil, "term") local link = require("Module:links").full_link({ term = particle, lang = data.lang }, "term") return { description = "{{{langname}}} {{w|phrasal verb}}s using the particle " .. link .. ".", displaytitle = "{{{langname}}} phrasal verbs with particle (" .. tagged_text .. ")", breadcrumb = tagged_text, parents = {{ name = "phrasal verbs", sort = particle }}, umbrella = false, } end end) return {LABELS = labels2, RAW_CATEGORIES = raw_categories, HANDLERS = handlers} 83ua8kolrila27ik4bitk7437mdbair مۆدیوول:category tree/modules 828 9313 36932 34753 2026-08-18T00:10:49Z Ghybu 12 بەپێی زمان (by language) 36932 Scribunto text/plain local labels = {} local raw_categories = {} local raw_handlers = {} local insert = table.insert local pattern_escape = require("Module:string utilities").pattern_escape ----------------------------------------------------------------------------- -- -- -- LABELS -- -- -- ----------------------------------------------------------------------------- labels["modules"] = { description = "{{{langname}}} [[Wiktionary:Modules|modules]], which contain Lua code to create and manage entries.", umbrella = { parents = {{name = "Modules", sort = " "}}, breadcrumb = "بەپێی زمان", }, parents = {{name = "{{{langcat}}}", raw = true}}, } labels["data modules"] = { description = "{{{langname}}} [[Wiktionary:Modules|modules]] containing data used by other modules.", umbrella = { parents = {{name = "Data modules", sort = " "}}, breadcrumb = "بەپێی زمان", }, breadcrumb = "data", parents = {"modules"}, } labels["dialect synonyms data modules"] = { description = "{{{langname}}} [[Wiktionary:Modules|modules]] containing data used by {{tl|dialect synonyms}}.", umbrella = { parents = {{name = "Dialect synonyms data modules", sort = " "}}, breadcrumb = "بەپێی زمان", }, breadcrumb = "dialect synonyms", parents = {"data modules"}, } labels["inflection modules"] = { description = "{{{langname}}} [[inflection]] [[Wiktionary:Modules|modules]], which contain Lua code for generating conjugation and declension tables.", umbrella = { parents = {{name = "Inflection modules", sort = " "}}, breadcrumb = "بەپێی زمان", }, breadcrumb = "inflection", parents = {"modules", {name = "inflection-table templates", sort = " "}}, } labels["testcase modules"] = { description = "{{{langname}}} [[testcase]] [[Wiktionary:Modules|modules]], which contain Lua code for testing other modules.", umbrella = { parents = {{name = "Testcase modules", sort = " "}}, breadcrumb = "بەپێی زمان", }, breadcrumb = "testcase", parents = {"modules"}, } ----------------------------------------------------------------------------- -- -- -- RAW CATEGORIES -- -- -- ----------------------------------------------------------------------------- --[=[ Correctly defining a new module type here: 1. The breadcrumb generally does not need to be given because there is code at the bottom of this file to generate the breadcrumb in a smart fashion by chopping off a suffix derived from the parent or any of its ancestors. 2. Module types can be nested under other module types, but also list them directly under 'Modules' as a secondary parent. (This violates a principle of non-duplication of categories but makes it much easier to locate a given module type.) ]=] raw_categories["Modules"] = { description = "This is a general holder category for modules.", additional = "For more information on what modules are and how they work, see [[Wiktionary:Scribunto]]. For a complete list of all modules, see [[Special:PrefixIndex/Module:|here]].", parents = {"Category:Wiktionary"}, } raw_categories["Uncategorized modules"] = { description = "Uncategorized modules.", additional = "Modules are placed here by [[Module:documentation]] under certain circumstances. See the documentation of that module for more info.", parents = { {name = "Modules", sort = " "} }, } raw_categories["Appendix modules"] = { preceding = "{{also|:Category:Appendix templates}}", description = "Modules with functions that generate content for or extract information from pages in the Appendix namespace.", parents = { "Modules" }, } raw_categories["Bot support modules"] = { description = "Modules for supporting individual bot accounts.", parents = { "Modules" }, } raw_categories["Category modules"] = { preceding = "{{also|:Category:Categorization templates|:Category:Category templates}}", description = "Modules for adding categories to pages or generating the description and subcategories of category pages.", parents = { "Modules" }, } raw_categories["Character info modules"] = { preceding = "{{also|:Category:Character info templates}}", description = "Modules containing information on individual characters, or containing functions generating such information.", parents = { "Modules" }, } raw_categories["Character insertion modules"] = { preceding = "{{also|:Category:Character insertion templates}}", description = "Modules that implement templates that provide easier ways to type characters that are not found in most keyboard layouts.", parents = { "Page generation modules", "Modules" }, } raw_categories["Collections modules"] = { description = "Modules containing functions used to implement collections (arrays, maps, etc.).", parents = { "Utility modules", "Modules" }, } raw_categories["Data modules"] = { description = "Modules that do not contain functions, but only export a table of data that is used by other modules.", additional = "Modules that are in this category should be imported using <code>mw.loadData</code> rather than <code>require</code>.", parents = { "Modules" }, } raw_categories["Character insertion data modules"] = { preceding = "{{also|:Category:Character insertion templates}}", description = "Modules containing data for use by {{temp|chars}}.", parents = { "Data modules", "Character insertion modules" }, } raw_categories["Dialect synonyms data modules"] = { preceding = "{{also|:Category:Character insertion templates}}", description = "Modules containing data for use by {{tl|dialect synonyms}}.", parents = { "Data modules" }, } raw_categories["Date modules"] = { description = "Modules that implement functionality to convert or otherwise manipulate dates in various calendar systems.", parents = { "Utility modules", "Modules" }, } raw_categories["Debugging modules"] = { description = "Modules used for debugging.", additional = "Some should only be used in sandbox modules or when using the " .. "[[mw:Extension:TemplateSandbox|{{MediaWiki:Templatesandbox-editform-legend}}]] button in the edit page of modules and templates.", parents = { "Modules" }, } raw_categories["Definition modules"] = { preceding = "{{also|:Category:Definition templates}}", description = "Modules that implement templates used in [[Wiktionary:Glossary#definition line|definition lines]] of entries.", parents = { "Page generation modules", "Modules" }, } raw_categories["Deprecated modules"] = { description = "Modules that should not be used, as their functions are performed by newer modules.", parents = { "Modules", "Category:Wiktionary maintenance" }, } raw_categories["Discussion modules"] = { preceding = "{{also|:Category:Discussion templates}}", description = "Modules concerning discussion pages.", parents = { "Modules" }, } raw_categories["Display text-generating modules"] = { description = "Modules that are used to generate display text.", additional = "Display text determines what is shown to the reader. In some languages it must be normalized, " .. "due to common errors caused by confusable characters, or so as to ensure a consistent display format.", parents = { "Modules" }, } raw_categories["Documentation modules"] = { preceding = "{{also|:Category:Documentation templates}}", description = "Modules for generating documentation pages.", parents = { "Modules" }, } raw_categories["Encoding modules"] = { description = "Modules for converting between different textual encodings.", parents = { "Utility modules", "Modules" }, } raw_categories["Entry-generating modules"] = { preceding = "{{also|:Category:Entry templates}}", description = "Modules with functions that are used to generate new entries.", parents = { "Modules" }, } raw_categories["Entry name-generating modules"] = { description = "Modules that generate entry names, which typically have certain diacritics stripped compared with the form in links and headwords.", parents = { "Modules" }, } raw_categories["External link modules"] = { preceding = "{{also|:Category:External link templates}}", description = "Modules that are used in [[:Category:External link templates|external link templates]], i.e. which link to websites outside of the MediaWiki Foundation purview.", parents = { "Page generation modules", "Modules" }, } raw_categories["Etymology modules"] = { preceding = "{{also|:Category:Etymology templates}}", description = "Modules that implement templates that define the etymology of entries.", parents = { "Page generation modules", "Modules" }, } raw_categories["Form-of modules"] = { preceding = "{{also|:Category:Form-of templates}}", description = "Modules that generate the definition line of non-lemma forms, e.g. verb forms and noun forms.", parents = { "Definition modules", "Page generation modules", "Modules" }, } raw_categories["Headword-line modules"] = { preceding = "{{also|:Category:Headword-line templates}}", description = "Modules that support [[:Category:Headword-line templates by language|headword-line templates]] for a specific language.", additional = "See also [[:Category:Headword-line templates]].", parents = { "Page generation modules", "Modules" }, } raw_categories["Inflection modules"] = { description = "Modules used to support [[:Category:Inflection-table templates by language|inflection templates]] for a specific language.", parents = { "Page generation modules", "Modules" }, } raw_categories["Internal link modules"] = { preceding = "{{also|:Category:Internal link templates}}", description = "Modules that are used in [[:Category:Internal link templates|internal link templates]], i.e. which link between Wiktionary entries.", parents = { "Page generation modules", "Modules" }, } raw_categories["Interwiki modules"] = { preceding = "{{also|:Category:Interwiki templates}}", description = "Modules that are used in [[:Category:Interwiki templates|interwiki templates]], i.e. which link to other MediaWiki projects.", parents = { "Page generation modules", "Modules" }, } raw_categories["JSON-generating modules"] = { description = "Modules with functions that generate data in JSON format.", parents = { "Modules" }, } raw_categories["Language and script modules"] = { description = "Modules that process language and script codes and return data on them.", parents = { "Modules" }, } raw_categories["List modules"] = { preceding = "{{also|:Category:List templates}}", description = "Modules that generate lists, tables or tree diagrams of entries or other structured data.", parents = { "Page generation modules", "Modules" }, } raw_categories["Maintenance modules"] = { preceding = "{{also|:Category:Maintenance templates}}", description = "Modules that implement templates used for maintaining entries.", additional = "Examples are cleanup templates (e.g. {{tl|attention}}), deletion templates (e.g. {{tl|rfd}}) and " .. "verification templates (e.g. {{tl|rfv}}).", parents = { "Modules" }, } raw_categories["Number modules"] = { preceding = "{{also|:Category:Number templates}}", description = "Modules that handle conversion and/or formatting of numbers and numerals in various representations.", parents = { "Utility modules", "Modules" }, } raw_categories["Page generation modules"] = { description = "Modules that generate parts of a mainspace page (e.g. headword line, definition, inflection, links, etc.).", parents = { "Modules" }, } raw_categories["Parameter parsing modules"] = { description = "Modules containing functions used to parse template parameters.", parents = { "Utility modules", "Modules" }, } raw_categories["Pronunciation modules"] = { preceding = "{{also|:Category:Pronunciation templates}}", description = "Modules that implement templates used to create the language-specific pronunciation of entries.", parents = { "Page generation modules", "Modules" }, } raw_categories["Pronunciation testcase modules"] = { description = "Modules used to test other pronunciation modules.", parents = { "Testcase modules", {name = "Pronunciation modules", sort = "Testcase"} }, } raw_categories["Quotation and usage example modules"] = { description = "Modules that implement templates used to format quotations and usage examples.", parents = { "Definition modules", "Page generation modules", "Modules" }, } raw_categories["Reference modules"] = { preceding = "{{also|:Category:Reference templates}}", description = "Modules that are used for [[:Category:Reference templates|reference templates]].", parents = { "Page generation modules", "Modules" }, } raw_categories["Sandbox modules"] = { description = "Test versions of modules intended for production use.", parents = { "Modules" }, } raw_categories["Semantic relation modules"] = { preceding = "{{also|:Category:Semantic relation templates}}", description = "Modules that implement templates used to indicate other terms semantically related to a " .. "particular sense, e.g. [[synonym]]s or [[antonym]]s.", parents = { "Page generation modules", "Modules" }, } raw_categories["Sortkey-generating modules"] = { description = "Modules that generate sortkeys, which determine the order of entry names in categories.", parents = { "Modules" }, } raw_categories["String modules"] = { description = "Modules containing functions used to manipulate strings.", parents = { "Utility modules", "Modules" }, } raw_categories["Swadesh modules"] = { description = "Modules containing [[Swadesh list]]s.", parents = { "Modules" }, } raw_categories["Template interface modules"] = { description = "Modules whose purpose is to provide an interface between templates and the functions of a module.", additional = "They are usually named <code>.../templates</code>, and the functions present within them usually all " .. "have only a \"frame\" parameter.", parents = { "Modules" }, } raw_categories["Testcase modules"] = { description = "Modules used to test other modules.", parents = { "Modules" }, } raw_categories["Failing testcase modules"] = { description = "Modules which contain failures in their unit tests.", additional = "This category is added automatically by [[Module:UnitTests]] when a test case fails.", parents = { "Testcase modules" }, } raw_categories["Tracking modules"] = { description = "Modules that add tracking templates.", parents = { "Debugging modules", "Modules" }, } raw_categories["Transliteration modules"] = { description = "Modules that automatically convert text in one script to another.", additional = "Most of them convert non-Latin scripts to Latin (romanisation/romanization), and are used by " .. "templates or modules to generate transliteration of text that is tagged with a particular language. Each " .. "language's transliteration module is specified in its data table (for which, see the category {{catlink|Language data modules}}).", parents = { "Modules" }, } raw_categories["Transliteration testcase modules"] = { description = "Modules used to test other transliteration modules.", parents = { "Testcase modules", {name = "Transliteration modules", sort = "Testcase"} }, } raw_categories["Unused modules"] = { description = "Unused modules.", parents = { "Modules" }, } raw_categories["User sandbox modules"] = { description = "Modules that are for personal use and testing by individual editors.", additional = "These should all begin with <code>User:</code> followed by the user's name. If several " .. "sandbox modules are needed by a single user, subpages can be created. These modules should not be used in real " .. "Wiktionary content pages, as all content on those pages should be editable by anyone and, if necessary, edit protected.", parents = { "Sandbox modules", "Modules" }, } raw_categories["Utility modules"] = { description = "Modules that serve some sort of utility purpose in various entries.", additional = "Avoid categorizing directly into this category, but use one of the more specific (and semantically " .. "well-defined) module categories. Note also that modules used by multiple languages should go directly in this " .. "category if necessary, while modules only used by one language should be in [[:Category:Language-specific utility modules]].", parents = { "Modules" }, } raw_categories["Language-specific utility modules"] = { description = "Modules that deal with several utilities needed by a certain language.", additional = "Usually their names end with {{cd|-utilities}} or {{cd|-common}} (preceded by the language code), " .. "although more specific utility modules that one language uses may reside here as well. If a utility is used by " .. "many languages, it should be in [[:Category:Utility modules]].", parents = {{name = "Utility modules", sort = " "}}, } raw_categories["Vote modules"] = { description = "Modules used to manage Wiktionary votes.", parents = { "Modules" }, } raw_categories["Wikitext parsing modules"] = { description = "Modules that contain functions that grab the wikitext of a page and get information from it by " .. "performing string operations on it.", parents = { "Modules" }, } -- Don't modify `raw_categories` while processing it, or items may be skipped. local new_cats = {} for raw_cat, obj in pairs(raw_categories) do local by_script = raw_cat .. " by script" if raw_cat ~= "Modules" and raw_cat ~= "Data modules" and not raw_categories[by_script] then new_cats[by_script] = { description = raw_cat .. ", categorized by the script they operate on or with.", additional = raw_cat .. " are " .. mw.getContentLanguage():lcfirst(obj.description), breadcrumb = "by script", parents = {{name = raw_cat, sort = " "}}, } end end for new_cat, obj in pairs(new_cats) do raw_categories[new_cat] = obj end ----------------------------------------------------------------------------- -- -- -- RAW HANDLERS -- -- -- ----------------------------------------------------------------------------- for _, mod_type in ipairs {"Entry name-generating", "Sortkey-generating", "Transliteration"} do insert(raw_handlers, function(data) local n, suffix = data.category:match(("^%s modules used by (%%d+) language(s?)$"):format(pattern_escape(mod_type))) -- Only match if there are no leading zeroes and the suffix is correct. if not (n and not n:match("^0%d") and suffix == (n == "1" and "" or "s")) then return end return { breadcrumb = ("used by %d language%s"):format(n, suffix), description = data.category .. ".", can_be_empty = true, parents = { {name = ("%s modules"):format(mod_type), sort = require("Module:category tree").numeral_sortkey(n)}, }, } end) end -- Add breadcrumb by chopping off the parent (or the parent's parent, etc.) from the end of the label, if possible. for key, data in pairs(raw_categories) do if not data.breadcrumb then local parent = data.parents[1] while true do if type(parent) == "string" then local parent_re = " " .. pattern_escape(mw.getContentLanguage():lcfirst(parent)) .. "$" if key:find(parent_re) then data.breadcrumb = key:gsub(parent_re, "") break end if raw_categories[parent] then parent = raw_categories[parent].parents[1] else break end else break end end end end return {LABELS = labels, RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers} jdbdyi3avh90j0o1aed4c31lxqcdoul مۆدیوول:pages 828 10674 36913 34456 2026-08-17T20:28:35Z Ghybu 12 36913 Scribunto text/plain local export = {} local string_utilities_module = "Module:string utilities" local concat = table.concat local find = string.find local format = string.format local getmetatable = getmetatable local get_current_section -- defined below local get_namespace_shortcut -- defined below local get_pagetype -- defined below local gsub = string.gsub local insert = table.insert local is_internal_title -- defined below local is_title -- defined below local lower = string.lower local match = string.match local new_title = mw.title.new local require = require local sub = string.sub local title_equals = mw.title.equals local tonumber = tonumber local type = type local ufind = mw.ustring.find local unstrip_nowiki = mw.text.unstripNoWiki --[==[ Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==] local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function ulower(...) ulower = require(string_utilities_module).lower return ulower(...) end local function trim(...) trim = require(string_utilities_module).trim return trim(...) end --[==[ Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] local current_frame local function get_current_frame() current_frame, get_current_frame = mw.getCurrentFrame(), nil return current_frame end local parent_frame local function get_parent_frame() parent_frame, get_parent_frame = (current_frame or get_current_frame()):getParent(), nil return parent_frame end local namespace_shortcuts local function get_namespace_shortcuts() namespace_shortcuts, get_namespace_shortcuts = { [4] = "WT", [10] = "T", [14] = "CAT", [100] = "AP", [110] = "WS", [118] = "RC", [828] = "MOD", }, nil return namespace_shortcuts end do local transcluded --[==[ Returns {true} if the current {{tl|#invoke:}} is being transcluded, or {false} if not. If the current {{tl|#invoke:}} is part of a template, for instance, this template will therefore return {true}. Note that if a template containing an {{tl|#invoke:}} is used on its own page (e.g. to display a demonstration), this function is still able to detect that this is transclusion. This is an improvement over the other method for detecting transclusion, which is to check the parent frame title against the current page title, which fails to detect transclusion in that instance.]==] function export.is_transcluded() if transcluded == nil then transcluded = (parent_frame or get_parent_frame()) and parent_frame:preprocess("<includeonly>1</includeonly>") == "1" or false end return transcluded end end do local preview --[==[ Returns {true} if the page is currently being viewed in preview, or {false} if not.]==] function export.is_preview() if preview == nil then preview = (current_frame or get_current_frame()):preprocess("{{REVISIONID}}") == "" end return preview end end --[==[ Returns {true} if the input is a title object, or {false} if not. This therefore '''includes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_internal_title` below.]==] function export.is_title(val) if not (val and type(val) == "table") then return false end local mt = getmetatable(val) -- There's no foolproof method for checking for a title object, but the -- __eq metamethod should be mw.title.equals unless the object has been -- seriously messed around with. return mt and type(mt) == "table" and getmetatable(mt) == nil and mt.__eq == title_equals and true or false end is_title = export.is_title --[==[ Returns {true} if the input is an internal title object, or {false} if not. An internal title object is a title object for a page on this wiki, such as [[example]]. This therefore '''excludes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_title` above.]==] function export.is_internal_title(title) -- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out. return is_title(title) and #title.prefixedText > 0 and #title.interwiki == 0 end is_internal_title = export.is_internal_title --[==[ Returns {true} if the input string is a valid link target, or {false} if not. This therefore '''includes''' link targets to other wikis, such as [[w:Example]], unlike `is_valid_page_name` below.]==] function export.is_valid_link_target(target) local target_type = type(target) if target_type == "string" then return is_title(new_title(target)) end error(format("bad argument #1 to 'is_valid_link_target' (string expected, got %s)", target_type), 2) end --[==[ Returns {true} if the input string is a valid page name on this wiki, or {false} if not. This therefore '''excludes''' page names on other wikis, such as [[w:Example]], unlike `is_valid_link_target` above.]==] function export.is_valid_page_name(name) local name_type = type(name) if name_type == "string" then return is_internal_title(new_title(name)) end error(format("bad argument #1 to 'is_valid_page_name' (string expected, got %s)", name_type), 2) end --[==[ Given a title object, returns a full link target which will always unambiguously link to it. For instance, the input {"foo"} (for the page [[foo]]) returns {":foo"}, as a leading colon always refers to mainspace, even when other namespaces might be assumed (e.g. when transcluding using `{{ }}` syntax). If `shortcut` is set, then the returned target will use the namespace shortcut, if any; for example, the title for `Template:foo` would return {"T:foo"} instead of {"Template:foo"}.]==] function export.get_link_target(title, shortcut) if not is_title(title) then error(format("bad argument #1 to 'is_valid_link_target' (title object expected, got %s)", type(title))) elseif title.interwiki ~= "" then return title.fullText elseif shortcut then local fragment = title.fragment if fragment == "" then return get_namespace_shortcut(title) .. ":" .. title.text end return get_namespace_shortcut(title) .. ":" .. title.text .. "#" .. fragment elseif title.namespace == 0 then return ":" .. title.fullText end return title.fullText end do local function find_sandbox(text) return find(text, "^User:.") or find(lower(text), "sandbox", 1, true) end local function get_transclusion_subtypes(title, main_type, documentation, page_suffix) local text, subtypes = title.text, {main_type} -- Any template/module with "sandbox" in the title. These are impossible -- to screen for more accurately, as there's no consistent pattern. Also -- any user sandboxes in the form (e.g.) "Template:User:...". local sandbox = find_sandbox(text) if sandbox then insert(subtypes, "sandbox") end -- Any template/module testcases (which can be labelled and/or followed -- by further subpages). local testcase = find(text, "./[Tt]estcases?%f[%L]") if testcase then -- Order "testcase" and "sandbox" based on where the patterns occur -- in the title. local n = sandbox and sandbox < testcase and 3 or 2 insert(subtypes, n, "testcase") end -- Any template/module documentation pages. if documentation then insert(subtypes, "documentation") end local final = subtypes[#subtypes] if not (final == main_type and not page_suffix or final == "sandbox") then insert(subtypes, "page") end return concat(subtypes, " ") end local function get_snippet_subtypes(title, main_type, documentation) local ns = title.namespace return get_transclusion_subtypes(title, ( ns == 2 and "user " or ns == 8 and match(title.text, "^Gadget-.") and "gadget " or "" ) .. main_type, documentation) end --[==[ Returns the page type of the input title object in a format which can be used in running text.]==] function export.get_pagetype(title) if not is_internal_title(title) then error(mw.dumpObject(title.fullText) .. " is not a valid page name.") end -- If possibly a documentation page, get the base title and set the -- `documentation` flag. local content_model, text, documentation = title.contentModel if content_model == "wikitext" then text = title.text if title.isSubpage and title.subpageText == "documentation" then local base_title = title.basePageTitle if base_title then title, content_model, text, documentation = base_title, base_title.contentModel, base_title.text, true end end end -- Content models have overriding priority, as they can appear in -- nonstandard places due to page content model changes. if content_model == "css" or content_model == "sanitized-css" then return get_snippet_subtypes(title, "stylesheet", documentation) elseif content_model == "javascript" then return get_snippet_subtypes(title, "script", documentation) elseif content_model == "json" then return get_snippet_subtypes(title, "JSON data", documentation) elseif content_model == "MassMessageListContent" then return get_snippet_subtypes(title, "mass message delivery list", documentation) -- Modules. elseif content_model == "Scribunto" then return get_transclusion_subtypes(title, "module", documentation, false) elseif content_model == "text" then return "page" -- ??? -- Otherwise, the content model is "wikitext", so check namespaces. elseif title.isTalkPage then return "talk page" end local ns = title.namespace -- Main namespace. if ns == 0 then return "entry" -- Wiktionary: elseif ns == 4 then return find_sandbox(title.text) and "sandbox" or "project page" -- Template: elseif ns == 10 then return get_transclusion_subtypes(title, "template", documentation, false) end -- Convert the namespace to lowercase, unless it contains a capital -- letter after the initial letter (e.g. MediaWiki, TimedText). Also -- normalize any underscores. local ns_text = gsub(title.nsText, "_", " ") if ufind(ns_text, "^%U*$", 2) then ns_text = ulower(ns_text) end -- User: if ns == 2 then return ns_text .. " " .. (title.isSubpage and "subpage" or "page") -- Category: and Appendix: elseif ns == 14 or ns == 100 then return ns_text -- Thesaurus: and Reconstruction: elseif ns == 110 or ns == 118 then return ns_text .. " entry" end return ns_text .. " page" end get_pagetype = export.get_pagetype end --[==[ Returns {true} if the input title object is for a content page, or {false} if not. A content page is a page that is considered part of the dictionary itself, and excludes pages for discussion, administration, maintenance etc.]==] function export.is_content_page(title) if not is_internal_title(title) then error(mw.dumpObject(title.fullText) .. " is not a valid page name.") end local ns = title.namespace -- (main), Appendix, Thesaurus, Citations, Reconstruction. return (ns == 0 or ns == 100 or ns == 110 or ns == 114 or ns == 118) and title.contentModel == "wikitext" end --[==[ Returns {true} if the input title object is for a documentation page, or {false} if not.]==] function export.is_documentation(title) return match(get_pagetype(title), "%f[%w]documentation%f[%W]") and true or false end --[==[ Returns {true} if the input title object is for a sandbox, or {false} if not. By default, sandbox documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] function export.is_sandbox(title, include_documentation) local pagetype = get_pagetype(title) return match(pagetype, "%f[%w]sandbox%f[%W]") and ( include_documentation or not match(pagetype, "%f[%w]documentation%f[%W]") ) and true or false end --[==[ Returns {true} if the input title object is for a testcase page, or {false} if not. By default, testcase documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] function export.is_testcase_page(title, include_documentation) local pagetype = get_pagetype(title) return match(pagetype, "%f[%w]testcase%f[%W]") and ( include_documentation or not match(pagetype, "%f[%w]documentation%f[%W]") ) and true or false end --[==[ Returns the namespace shortcut for the input title object, or else the namespace text. For example, a `Template:` title returns {"T"}, a `Module:` title returns {"MOD"}, and a `User:` title returns {"User"}.]==] function export.get_namespace_shortcut(title) return (namespace_shortcuts or get_namespace_shortcuts())[title.namespace] or title.nsText end get_namespace_shortcut = export.get_namespace_shortcut do local function check_level(lvl) if type(lvl) ~= "number" then error("Heading levels must be numbers.") elseif lvl < 1 or lvl > 6 or lvl % 1 ~= 0 then error("Heading levels must be integers between 1 and 6.") end return lvl end --[==[ A helper function which iterates over the headings in `text`, which should be the content of a page or (main) section. Each iteration returns three values: `sec` (the section title), `lvl` (the section level) and `loc` (the index of the section in the given text, from the first equals sign). The section title will be automatically trimmed, and any HTML entities will be resolved. The optional parameter `a` (which should be an integer between 1 and 6) can be used to ensure that only headings of the specified level are iterated over. If `b` is also given, then they are treated as a range. The optional parameters `a` and `b` can be used to specify a range, so that only headings with levels in that range are returned.]==] local function find_headings(text, a, b) a = a and check_level(a) or nil b = b and check_level(b) or a or nil local start, loc, lvl, sec = 1 return function() repeat loc, lvl, sec, start = match(text, "()%f[^%z\n](==?=?=?=?=?)([^\n]+)%2[\t ]*%f[%z\n]()", start) lvl = lvl and #lvl until not (sec and a) or (lvl >= a and lvl <= b) return sec and trim(decode_entities(sec)) or nil, lvl, loc end end local function _get_section(content, name, level) if not (content and name) then return nil elseif find(name, "\n", 1, true) then error("Heading name cannot contain a newline.") end level = level and check_level(level) or nil name = trim(decode_entities(name)) local start for sec, lvl, loc in find_headings(content, level and 1 or nil, level) do if start and lvl <= level then return sub(content, start, loc - 1) elseif not start and (not level or lvl == level) and sec == name then start, level = loc, lvl end end return start and sub(content, start) end --[==[ A helper function to return the content of a page section. `content` is raw wikitext, `name` is the requested section, and `level` is an optional parameter that specifies the required section heading level. If `level` is not supplied, then the first section called `name` is returned. `name` can either be a string or table of section names. If a table, each name represents a section that has the next as a subsection. For example, { {"Spanish", "Noun"}} will return the first matching section called "Noun" under a section called "Spanish". These do not have to be at adjacent levels ("Noun" might be L4, while "Spanish" is L2). If `level` is given, it refers to the last name in the table (i.e. the name of the section to be returned). The returned section includes all of its subsections. If no matching section is found, return {nil}.]==] function export.get_section(content, names, level) if type(names) ~= "table" then return _get_section(content, names, level) end local i = 1 local name = names[i] if not name then error("Must specify at least 1 section.") end while true do local nxt_i = i + 1 local nxt = names[nxt_i] if nxt == nil then return _get_section(content, name, level) end content = _get_section(content, name) if content == nil then return nil elseif i == 6 then error("Not possible specify more than 6 sections: headings only go up to level 6.") end i = nxt_i name = names[i] end return content end end do local current_section --[==[ A function which returns the number of the page section which contains the current {#invoke}, or {0} if the section can't be determined.]==] function export.get_current_section() if current_section ~= nil then return current_section end local frame = parent_frame or get_parent_frame() while frame do if find(frame:getTitle(), "^Module:") then current_section = 0 return 0 end frame = frame:getParent() end local extension_tag = (current_frame or get_current_frame()).extensionTag -- We determine the section via the heading strip marker count, since they're numbered sequentially, but the only way to do this is to generate a fake heading via frame:preprocess(). The native parser assigns each heading a unique marker, but frame:preprocess() will return copies of older markers if the heading is identical to one further up the page, so the fake heading has to be unique to the page. The best way to do this is to feed it a heading containing a nowiki marker (which we will need later), since those are always unique. local nowiki_marker = extension_tag(current_frame, "nowiki") -- Note: heading strip markers have a different syntax to the ones used for tags. local h = tonumber(match( current_frame:preprocess("=" .. nowiki_marker .. "="), "\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127" )) -- For some reason, [[Special:ExpandTemplates]] doesn't generate a heading strip marker, so if that happens we simply abort early. if not h then return 0 end -- The only way to get the section number is to increment the heading count, so we store the offset in nowiki strip markers which can be retrieved by procedurally unstripping nowiki markers, counting backwards until we find a match. local n, offset = tonumber(match( nowiki_marker, "\127'\"`UNIQ%-%-nowiki%-([%dA-F]+)%-QINU`\"'\127" ), 16) while not offset and n > 0 do n = n - 1 offset = match( unstrip_nowiki(format("\127'\"`UNIQ--nowiki-%08X-QINU`\"'\127", n)), "^HEADING\1(%d+)" -- Prefix "HEADING\1" prevents collisions. ) end offset = offset and (offset + 1) or 0 extension_tag(current_frame, "nowiki", "HEADING\1" .. offset) current_section = h - offset return current_section end get_current_section = export.get_current_section end do local L2_sections, current_L2 local function get_L2_sections() L2_sections, get_L2_sections = mw.loadData("Module:headword/data").page.L2_sections, nil return L2_sections end --[==[ A function which returns the name of the L2 language section which contains the current {#invoke}.]==] function export.get_current_L2() if current_L2 ~= nil then return current_L2 or nil -- Return nil if current_L2 is false (i.e. there's no L2). end local section = get_current_section() while section > 0 do local L2 = (L2_sections or get_L2_sections())[section] if L2 then current_L2 = L2 return L2 end section = section - 1 end current_L2 = false return nil end end return export gdpkp4jhb7nfkcr0r3uwx8kn3hzfj9h 36930 36913 2026-08-17T23:47:30Z Ghybu 12 "export.get current section()" failed to find the sections. It has been modified for the Sorani wiki to enable their detection. 36930 Scribunto text/plain local export = {} local string_utilities_module = "Module:string utilities" local concat = table.concat local find = string.find local format = string.format local getmetatable = getmetatable local get_current_section -- defined below local get_namespace_shortcut -- defined below local get_pagetype -- defined below local gsub = string.gsub local insert = table.insert local is_internal_title -- defined below local is_title -- defined below local lower = string.lower local match = string.match local new_title = mw.title.new local require = require local sub = string.sub local title_equals = mw.title.equals local tonumber = tonumber local type = type local ufind = mw.ustring.find local unstrip_nowiki = mw.text.unstripNoWiki --[==[ Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==] local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function ulower(...) ulower = require(string_utilities_module).lower return ulower(...) end local function trim(...) trim = require(string_utilities_module).trim return trim(...) end --[==[ Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==] local current_frame local function get_current_frame() current_frame, get_current_frame = mw.getCurrentFrame(), nil return current_frame end local parent_frame local function get_parent_frame() parent_frame, get_parent_frame = (current_frame or get_current_frame()):getParent(), nil return parent_frame end local namespace_shortcuts local function get_namespace_shortcuts() namespace_shortcuts, get_namespace_shortcuts = { [4] = "WT", [10] = "T", [14] = "CAT", [100] = "AP", [110] = "WS", [118] = "RC", [828] = "MOD", }, nil return namespace_shortcuts end do local transcluded --[==[ Returns {true} if the current {{tl|#invoke:}} is being transcluded, or {false} if not. If the current {{tl|#invoke:}} is part of a template, for instance, this template will therefore return {true}. Note that if a template containing an {{tl|#invoke:}} is used on its own page (e.g. to display a demonstration), this function is still able to detect that this is transclusion. This is an improvement over the other method for detecting transclusion, which is to check the parent frame title against the current page title, which fails to detect transclusion in that instance.]==] function export.is_transcluded() if transcluded == nil then transcluded = (parent_frame or get_parent_frame()) and parent_frame:preprocess("<includeonly>1</includeonly>") == "1" or false end return transcluded end end do local preview --[==[ Returns {true} if the page is currently being viewed in preview, or {false} if not.]==] function export.is_preview() if preview == nil then preview = (current_frame or get_current_frame()):preprocess("{{REVISIONID}}") == "" end return preview end end --[==[ Returns {true} if the input is a title object, or {false} if not. This therefore '''includes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_internal_title` below.]==] function export.is_title(val) if not (val and type(val) == "table") then return false end local mt = getmetatable(val) -- There's no foolproof method for checking for a title object, but the -- __eq metamethod should be mw.title.equals unless the object has been -- seriously messed around with. return mt and type(mt) == "table" and getmetatable(mt) == nil and mt.__eq == title_equals and true or false end is_title = export.is_title --[==[ Returns {true} if the input is an internal title object, or {false} if not. An internal title object is a title object for a page on this wiki, such as [[example]]. This therefore '''excludes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_title` above.]==] function export.is_internal_title(title) -- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out. return is_title(title) and #title.prefixedText > 0 and #title.interwiki == 0 end is_internal_title = export.is_internal_title --[==[ Returns {true} if the input string is a valid link target, or {false} if not. This therefore '''includes''' link targets to other wikis, such as [[w:Example]], unlike `is_valid_page_name` below.]==] function export.is_valid_link_target(target) local target_type = type(target) if target_type == "string" then return is_title(new_title(target)) end error(format("bad argument #1 to 'is_valid_link_target' (string expected, got %s)", target_type), 2) end --[==[ Returns {true} if the input string is a valid page name on this wiki, or {false} if not. This therefore '''excludes''' page names on other wikis, such as [[w:Example]], unlike `is_valid_link_target` above.]==] function export.is_valid_page_name(name) local name_type = type(name) if name_type == "string" then return is_internal_title(new_title(name)) end error(format("bad argument #1 to 'is_valid_page_name' (string expected, got %s)", name_type), 2) end --[==[ Given a title object, returns a full link target which will always unambiguously link to it. For instance, the input {"foo"} (for the page [[foo]]) returns {":foo"}, as a leading colon always refers to mainspace, even when other namespaces might be assumed (e.g. when transcluding using `{{ }}` syntax). If `shortcut` is set, then the returned target will use the namespace shortcut, if any; for example, the title for `Template:foo` would return {"T:foo"} instead of {"Template:foo"}.]==] function export.get_link_target(title, shortcut) if not is_title(title) then error(format("bad argument #1 to 'is_valid_link_target' (title object expected, got %s)", type(title))) elseif title.interwiki ~= "" then return title.fullText elseif shortcut then local fragment = title.fragment if fragment == "" then return get_namespace_shortcut(title) .. ":" .. title.text end return get_namespace_shortcut(title) .. ":" .. title.text .. "#" .. fragment elseif title.namespace == 0 then return ":" .. title.fullText end return title.fullText end do local function find_sandbox(text) return find(text, "^User:.") or find(lower(text), "sandbox", 1, true) end local function get_transclusion_subtypes(title, main_type, documentation, page_suffix) local text, subtypes = title.text, {main_type} -- Any template/module with "sandbox" in the title. These are impossible -- to screen for more accurately, as there's no consistent pattern. Also -- any user sandboxes in the form (e.g.) "Template:User:...". local sandbox = find_sandbox(text) if sandbox then insert(subtypes, "sandbox") end -- Any template/module testcases (which can be labelled and/or followed -- by further subpages). local testcase = find(text, "./[Tt]estcases?%f[%L]") if testcase then -- Order "testcase" and "sandbox" based on where the patterns occur -- in the title. local n = sandbox and sandbox < testcase and 3 or 2 insert(subtypes, n, "testcase") end -- Any template/module documentation pages. if documentation then insert(subtypes, "documentation") end local final = subtypes[#subtypes] if not (final == main_type and not page_suffix or final == "sandbox") then insert(subtypes, "page") end return concat(subtypes, " ") end local function get_snippet_subtypes(title, main_type, documentation) local ns = title.namespace return get_transclusion_subtypes(title, ( ns == 2 and "user " or ns == 8 and match(title.text, "^Gadget-.") and "gadget " or "" ) .. main_type, documentation) end --[==[ Returns the page type of the input title object in a format which can be used in running text.]==] function export.get_pagetype(title) if not is_internal_title(title) then error(mw.dumpObject(title.fullText) .. " is not a valid page name.") end -- If possibly a documentation page, get the base title and set the -- `documentation` flag. local content_model, text, documentation = title.contentModel if content_model == "wikitext" then text = title.text if title.isSubpage and title.subpageText == "documentation" then local base_title = title.basePageTitle if base_title then title, content_model, text, documentation = base_title, base_title.contentModel, base_title.text, true end end end -- Content models have overriding priority, as they can appear in -- nonstandard places due to page content model changes. if content_model == "css" or content_model == "sanitized-css" then return get_snippet_subtypes(title, "stylesheet", documentation) elseif content_model == "javascript" then return get_snippet_subtypes(title, "script", documentation) elseif content_model == "json" then return get_snippet_subtypes(title, "JSON data", documentation) elseif content_model == "MassMessageListContent" then return get_snippet_subtypes(title, "mass message delivery list", documentation) -- Modules. elseif content_model == "Scribunto" then return get_transclusion_subtypes(title, "module", documentation, false) elseif content_model == "text" then return "page" -- ??? -- Otherwise, the content model is "wikitext", so check namespaces. elseif title.isTalkPage then return "talk page" end local ns = title.namespace -- Main namespace. if ns == 0 then return "entry" -- Wiktionary: elseif ns == 4 then return find_sandbox(title.text) and "sandbox" or "project page" -- Template: elseif ns == 10 then return get_transclusion_subtypes(title, "template", documentation, false) end -- Convert the namespace to lowercase, unless it contains a capital -- letter after the initial letter (e.g. MediaWiki, TimedText). Also -- normalize any underscores. local ns_text = gsub(title.nsText, "_", " ") if ufind(ns_text, "^%U*$", 2) then ns_text = ulower(ns_text) end -- User: if ns == 2 then return ns_text .. " " .. (title.isSubpage and "subpage" or "page") -- Category: and Appendix: elseif ns == 14 or ns == 100 then return ns_text -- Thesaurus: and Reconstruction: elseif ns == 110 or ns == 118 then return ns_text .. " entry" end return ns_text .. " page" end get_pagetype = export.get_pagetype end --[==[ Returns {true} if the input title object is for a content page, or {false} if not. A content page is a page that is considered part of the dictionary itself, and excludes pages for discussion, administration, maintenance etc.]==] function export.is_content_page(title) if not is_internal_title(title) then error(mw.dumpObject(title.fullText) .. " is not a valid page name.") end local ns = title.namespace -- (main), Appendix, Thesaurus, Citations, Reconstruction. return (ns == 0 or ns == 100 or ns == 110 or ns == 114 or ns == 118) and title.contentModel == "wikitext" end --[==[ Returns {true} if the input title object is for a documentation page, or {false} if not.]==] function export.is_documentation(title) return match(get_pagetype(title), "%f[%w]documentation%f[%W]") and true or false end --[==[ Returns {true} if the input title object is for a sandbox, or {false} if not. By default, sandbox documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] function export.is_sandbox(title, include_documentation) local pagetype = get_pagetype(title) return match(pagetype, "%f[%w]sandbox%f[%W]") and ( include_documentation or not match(pagetype, "%f[%w]documentation%f[%W]") ) and true or false end --[==[ Returns {true} if the input title object is for a testcase page, or {false} if not. By default, testcase documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==] function export.is_testcase_page(title, include_documentation) local pagetype = get_pagetype(title) return match(pagetype, "%f[%w]testcase%f[%W]") and ( include_documentation or not match(pagetype, "%f[%w]documentation%f[%W]") ) and true or false end --[==[ Returns the namespace shortcut for the input title object, or else the namespace text. For example, a `Template:` title returns {"T"}, a `Module:` title returns {"MOD"}, and a `User:` title returns {"User"}.]==] function export.get_namespace_shortcut(title) return (namespace_shortcuts or get_namespace_shortcuts())[title.namespace] or title.nsText end get_namespace_shortcut = export.get_namespace_shortcut do local function check_level(lvl) if type(lvl) ~= "number" then error("Heading levels must be numbers.") elseif lvl < 1 or lvl > 6 or lvl % 1 ~= 0 then error("Heading levels must be integers between 1 and 6.") end return lvl end --[==[ A helper function which iterates over the headings in `text`, which should be the content of a page or (main) section. Each iteration returns three values: `sec` (the section title), `lvl` (the section level) and `loc` (the index of the section in the given text, from the first equals sign). The section title will be automatically trimmed, and any HTML entities will be resolved. The optional parameter `a` (which should be an integer between 1 and 6) can be used to ensure that only headings of the specified level are iterated over. If `b` is also given, then they are treated as a range. The optional parameters `a` and `b` can be used to specify a range, so that only headings with levels in that range are returned.]==] local function find_headings(text, a, b) a = a and check_level(a) or nil b = b and check_level(b) or a or nil local start, loc, lvl, sec = 1 return function() repeat loc, lvl, sec, start = match(text, "()%f[^%z\n](==?=?=?=?=?)([^\n]+)%2[\t ]*%f[%z\n]()", start) lvl = lvl and #lvl until not (sec and a) or (lvl >= a and lvl <= b) return sec and trim(decode_entities(sec)) or nil, lvl, loc end end local function _get_section(content, name, level) if not (content and name) then return nil elseif find(name, "\n", 1, true) then error("Heading name cannot contain a newline.") end level = level and check_level(level) or nil name = trim(decode_entities(name)) local start for sec, lvl, loc in find_headings(content, level and 1 or nil, level) do if start and lvl <= level then return sub(content, start, loc - 1) elseif not start and (not level or lvl == level) and sec == name then start, level = loc, lvl end end return start and sub(content, start) end --[==[ A helper function to return the content of a page section. `content` is raw wikitext, `name` is the requested section, and `level` is an optional parameter that specifies the required section heading level. If `level` is not supplied, then the first section called `name` is returned. `name` can either be a string or table of section names. If a table, each name represents a section that has the next as a subsection. For example, { {"Spanish", "Noun"}} will return the first matching section called "Noun" under a section called "Spanish". These do not have to be at adjacent levels ("Noun" might be L4, while "Spanish" is L2). If `level` is given, it refers to the last name in the table (i.e. the name of the section to be returned). The returned section includes all of its subsections. If no matching section is found, return {nil}.]==] function export.get_section(content, names, level) if type(names) ~= "table" then return _get_section(content, names, level) end local i = 1 local name = names[i] if not name then error("Must specify at least 1 section.") end while true do local nxt_i = i + 1 local nxt = names[nxt_i] if nxt == nil then return _get_section(content, name, level) end content = _get_section(content, name) if content == nil then return nil elseif i == 6 then error("Not possible specify more than 6 sections: headings only go up to level 6.") end i = nxt_i name = names[i] end return content end end do local current_section --[==[ A function which returns the number of the page section which contains the current {#invoke}, or {0} if the section can't be determined.]==] function export.get_current_section() if current_section ~= nil then return current_section end local frame = parent_frame or get_parent_frame() while frame do if find(frame:getTitle(), "^Module:") then current_section = 0 return 0 end frame = frame:getParent() end local current = current_frame or get_current_frame() local extension_tag = current.extensionTag -- CKB: an empty nowiki does not produce a marker. -- Therefore, we give it some content. local nowiki_marker = extension_tag( current, "nowiki", "CKBSEC" ) -- Generate an artificial heading and retrieve its number. local h = tonumber(match( current:preprocess("=" .. nowiki_marker .. "="), "\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127" )) if not h then current_section = 0 return 0 end -- Retrieve the number of the nowiki marker. local n, offset = tonumber(match( nowiki_marker, "\127'\"`UNIQ%-%-nowiki%-([%dA-F]+)%-QINU`\"'\127" ), 16) -- Search for the offset in previous markers. while not offset and n > 0 do n = n - 1 offset = match( unstrip_nowiki( format( "\127'\"`UNIQ--nowiki-%08X-QINU`\"'\127", n ) ), "^CKBSEC\1(%d+)" ) end offset = offset and tonumber(offset) or 0 -- Store the offset. extension_tag( current, "nowiki", "CKBSEC\1" .. offset ) -- On ckb, the first generated heading is h = 0. -- MediaWiki sections start at 1. current_section = h - offset + 1 return current_section end get_current_section = export.get_current_section end do local L2_sections, current_L2 local function get_L2_sections() L2_sections, get_L2_sections = mw.loadData("Module:headword/data").page.L2_sections, nil return L2_sections end --[==[ A function which returns the name of the L2 language section which contains the current {#invoke}.]==] function export.get_current_L2() if current_L2 ~= nil then return current_L2 or nil -- Return nil if current_L2 is false (i.e. there's no L2). end local section = get_current_section() while section > 0 do local L2 = (L2_sections or get_L2_sections())[section] if L2 then current_L2 = L2 return L2 end section = section - 1 end current_L2 = false return nil end end return export k4p2ffbzn0qobygq5x7ic24qc83h777 automatic 0 11054 36951 35174 2026-08-18T03:41:10Z Ghybu 12 /* ئینگلیزی */ 36951 wikitext text/x-wiki == ئینگلیزی == ===وشەڕەتناسی === {{واڵا}} ===گۆکردن=== * {{IPA|en|/ˌɔː.təˈmæt.ɪk/|a=UK}} * {{IPA|en|/ˌɔː.təˈmæt.ɪk/|[ˌɔː.ɾəˈmæɾ.ɪk]|a=US}} ** {{IPA|en|/ˌɑː.təˈmæt.ɪk/|[ˌɑː.ɾəˈmæɾ.ɪk]|a=cot-caught}} *** {{audio|en|en-us-automatic.ogg|a=California}} ==== ھاوەڵناو ==== {{en-adj}} # شتێک کە بۆ خۆی کاردەکات و پێویستی بە کۆنترۆڵکردن لەلایەن [[مرۆڤ|مرۆڤەوە]] نییە #: {{ux|en|The automatic pilot [[system]] on the [[airplane]] kept it on [[course]] even during [[turbulence]].|سیستەمە لێخوڕە خۆکارەکە لەسەر فڕۆکەکە لەسەر ڕێڕەو ھێشتییەوە تەنانەت لە کاتی ھەڵبەز و دابەز.}} #: {{ux|en|The automatic doors opened as I approached the [[entrance]] to the store.|دەرگا ئۆتۆماتیکییەکان کرانەوە کە گەشتم بە بەردەمی فرۆشگاکە.}} # ڕوودان بەبێ [[بیرکردنەوە]] #: {{ux|en|Breathing is an automatic [[function]] of the body.|[[ھەناسەدان]] ئەرکێکی خۆنەویستانەی لەشە.}} # شتێک کە ھەمیشە ڕوودەدات لە ئەنجامی شتێکدا #: {{ux|en|A fine for this offence is automatic.|سزا بۆ ئەم تاوانە ھەمیشە ھەیە.}} ==== ناو ==== {{en-noun}} # [[چەک|چەکێک]] کە خۆی پڕدەکاتەوە [[ھەرچەندە]] دەست لەسەر [[پەلەپیتکە|پەلەپیتکەکە]] دابنێیت #: {{ux|en|The gunman opened fire with an automatic.|چەکدارەکە بە چەکێکی خۆکار دەستی بە تەقە کرد.}} # ئۆتۆمبێلێک کە [[خۆکارانە]] گێڕ دەگۆڕێت #: {{ux|en|Kate drives an automatic.|کەیت ئۆتۆمبێلێکی گێڕ ئۆتۆماتیکی ھەیە.}} 2242tcsb625qxo0fph89d3u6zvexbk3 keep 0 11064 36948 35217 2026-08-18T03:01:49Z Ghybu 12 /* کردار */ 36948 wikitext text/x-wiki == ئینگلیزی == ===گۆکردن=== * {{enPR|kēp}}, {{IPA|en|/kiːp/}} ** {{IPA|en|[kiːp]|[kʰɪjp]|a=RP}} ** {{IPA|en|[kʰɪjp]|a=SSB,Southern US}} ** {{IPA|en|[k̟çi(ː)p]|a=US}} ** {{IPA|en|[k(ʰ)i(ː)p]|a=CA,Scotland}} * {{audio|en|en-us-keep.ogg|a=US}} * {{audio|en|en-au-keep.ogg|a=AU}} * {{rhymes|en|iːp|s=1}} ===کار=== {{head|en|کار}} # [[پاراستن]] #: {{ux|en|He kept [[all]] her letters.|تەواوی [[نامە|نامەکانیی]] پاراست.}} #: {{ux|en|She handed the [[waiter]] a hundred dollar [[bill]] and told him to keep the [[change]].|پارەیەکی ١٠٠ دا بە [[گارسۆن|گارسۆنەکە]] و پێی گوت [[باقی|باقییەکەی]] ھەڵبگرە.}} # دانان یان [[ھەڵگرتن|ھەڵگرتنی]] شتێک لە شوێنێک #: {{ux|en|Keep your [[passport]] in a safe place.|پاسپۆرتەکەت لە شوێنێکی [[سەلامەت]] ھەڵبگرە.}} #: {{ux|en|Where do you keep the [[sugar]]?|شەکرەکە لە کوێ دەدەنێیت؟}} # ھەبوونی شتێک بۆ کەسێک #: {{ux|en|Please keep a [[seat]] for me.|تکایە جێگایەکم بۆ بگرە.}} #: {{ux|en|The man in the shop said he'd keep it for me until Friday.|پیاوەکە لە فرۆشگاکە گوتی بۆم دادەنێت تاوەکو ھەینی.}} # باوەشمان کرد بە یەکدیدا بۆ مانەوە بە گەرمی #: {{ux|en|We huddled together to keep warm.|باوەشمان کرد بە یەکدا بۆ مانەوە بە گەرمی.}} #: {{ux|en|I could not keep silent any longer.|نەمدەتوانی چی دیکە بێدەنگ بم.}} # بەردەوام بوون لە کردنی شتێک #: {{ux|en|Keep smiling!|[[بزە]] بکە!}} #: {{ux|en|Why does everyone keep saying that?|بۆچی ھەموان بەردەوام ئەوە دەڵێن؟}} # زانینی شتێک و ئەوەی بە کەس نەڵێیت #: {{ux|en|Can you keep a [[secret]]?|دەتوانیت [[نھێنی]] بپارێزیت؟}} #: {{ux|en|She kept her [[past]] secret from us all.|ڕابردووی بە نھێنی ھێشتەوە لە ھەموومان.}} # کردنی ئەوەی کە [[بەڵێن|بەڵێنت]] داوە #: {{ux|en|She kept her [[promise]] to visit them.|بەڵێنەکەی پاراست بەوەی سەردانیان بکات.}} #: {{ux|en|Mary kept her word and Henry was never informed.|ماری بەڵێنەکەی پاراست و ھێنری ھەرگیز پێی نەگوترا.}} # نووسینی شتێک وەک تۆمار #: {{ux|en|She kept a [[diary]] for over twenty years.|یادنامەیەکی بۆ بیست ساڵ نووسی.}} #: {{ux|en|Keep a note of where each item can be found.|ئەوە بنووسە کە ھەر شتێک لە کوێیە.}} # ھەبوونی ئاژەڵ و بەخێوکردنی #: {{ux|en|My [[grandmother]] kept chickens in her back yard.|داپیرەم مریشکی ھەبوو لە [[حەوشە|حەوشەی]] پشتەوە.}} #: {{ux|en|Residents are not allowed to keep pets.|ھاوڵاتییەکان ڕێگایان پێنادرێت ئاژەڵی ماڵییان ھەبێت.}} # ھەبوونی فرۆشگا یان چێشتخانەیەک و بەڕێوەبردنی #: {{ux|en|Her father kept a grocer's shop.|باوکی فرۆشگایەکی سەوزەفرۆشی ھەبوو.}} # دابینکردنی ئەوەی کە پێویستە بۆ کەسێک تاوەکو بژی #: {{ux|en|He scarcely earns enough to keep himself and his family.|بە ئەستەم بەشی پێویست قازانج دەکات بۆ ژیاندنی خۆی و خێزانەکەی.}} #: {{ux|en|He kept himself by giving private lessons.|خۆی دەژیاند بە گوتنەوەی وانەی تایبەت.}} # دواخستنی کەسێک #: {{ux|en|You're an hour late—what kept you?|یەک کاتژمێر دواکەوتوویت ـ چی دوایخستیت؟}} #: {{ux|en|I won't keep you long. I've just got a [[couple]] of quick questions.|دواتناخەم بۆ زۆر. ژمارەیەک پرسیاری خێرام ھەن.}} # بۆ باسکردن یان پرسین لە [[تەندروستی]] کەسێک #: {{ux|en|How is your mother keeping?|تەندروستی دایکت چۆنە؟}} #: {{ux|en|We're all keeping well.|ھەموومان تەندروستیمان باشە.}} # مانەوە لە دۆخێکی باش #: {{ux|en|Milk and cream should keep [[quite]] well in a fridge.|شیر و کرێم دەکرێت زۆر باش لە بەفرگر بمێننەوە.}} #: {{ux|en|Finish off the banana—it won't keep.|مۆزەکە تەواو بکە ـ باش نامێنێتەوە.}} # پاراستنی کەسێک لە شتێک #: {{ux|en|May the Lord bless you and keep you.|خودا ڕەحمت پێبکات و بتپارێزێت.}} #: {{ux|en|His only [[thought]] was to keep the boy from harm.|تەنھا بیرکردنەوەی ئەوە بوو کوڕەکە لە مەترسی بپارێزێت.}} ====ناو==== # خواردن، [[جلوبەرگ]]، و ھەموو ئەو شتانەی کە کەسێک پێویستییەتی بۆ ژیان #: {{ux|en|It's about time you got a [[job]] to earn your keep.|لەسەر کات وەستاوە کە کارێک بدۆزیتەوە کە بژێوی خۆت پەیدا بکەیت.}} # تاوەرێکی گەورەی بەھێز کە وەک بەشێکی قەڵایەکی کۆن درووستکراوە oeed5d89elmplgc51jomi746a2uaj9a مۆدیوول:test 828 11481 36914 36909 2026-08-17T21:54:05Z Ghybu 12 36914 Scribunto text/plain function export.test_section() local frame = mw.getCurrentFrame() local extension_tag = frame.extensionTag local nowiki_marker = extension_tag(frame, "nowiki") local preprocessed = frame:preprocess( "=" .. nowiki_marker .. "=" ) return "<pre>" .. "NOWIKI:\n" .. nowiki_marker .. "\n\nPREPROCESS:\n" .. preprocessed .. "</pre>" end 2x7areyed37j80ltygauo1x1h08h10u 36915 36914 2026-08-17T21:55:22Z Ghybu 12 36915 Scribunto text/plain function export.get_current_section() local frame = mw.getCurrentFrame() local extension_tag = frame.extensionTag local nowiki_marker = extension_tag(frame, "nowiki") local preprocessed = frame:preprocess( "=" .. nowiki_marker .. "=" ) return "<pre>" .. "NOWIKI:\n" .. nowiki_marker .. "\n\nPREPROCESS:\n" .. preprocessed .. "</pre>" end l0ga7qtamwl0du9g63dbwgoq16yij9i 36916 36915 2026-08-17T21:57:30Z Ghybu 12 36916 Scribunto text/plain local export = {} function export.get_current_section() local frame = mw.getCurrentFrame() local extension_tag = frame.extensionTag local nowiki_marker = extension_tag(frame, "nowiki") local preprocessed = frame:preprocess( "=" .. nowiki_marker .. "=" ) return "<pre>" .. "NOWIKI:\n" .. nowiki_marker .. "\n\nPREPROCESS:\n" .. preprocessed .. "</pre>" end return export k26jzbu5neow4ncfy6pcor068ofoen7 36929 36916 2026-08-17T23:47:11Z Ghybu 12 پەڕەکەی واڵا کردەوە 36929 Scribunto text/plain phoiac9h4m842xq45sp7s6u21eteeq1 بەکارھێنەر:Ghybu/test 2 11482 36919 36912 2026-08-17T22:29:16Z Ghybu 12 36919 wikitext text/x-wiki == یەکەم == {{#invoke:Pages|get_current_section}} === بەش === {{#invoke:Pages|get_current_section}} == دووەم == {{#invoke:Pages|get_current_section}} === بەش === {{#invoke:Pages|get_current_section}} 938zil969mu2m97nbymhqllax4b7iko 36920 36919 2026-08-17T22:35:19Z Ghybu 12 36920 wikitext text/x-wiki == یەکەم == {{#invoke:pages|get_current_section}} === بەش === {{#invoke:pages|get_current_section}} == دووەم == {{#invoke:pages|get_current_section}} === بەش === {{#invoke:pages|get_current_section}} tg84pf347i3d79qu3gquy18af0zqd8a 36921 36920 2026-08-17T22:38:11Z Ghybu 12 36921 wikitext text/x-wiki aaaa {{#invoke:pages|get_current_section}} o2jnt6avsjuwrwtgfr6me22d9gnh40w 36922 36921 2026-08-17T22:43:51Z Ghybu 12 پووچەڵکردنەوەی پێداچوونەوەی [[Special:Diff/36921|36921]] لە لایەن [[Special:Contributions/Ghybu|Ghybu]] ([[User talk:Ghybu|لێدوان]]) 36922 wikitext text/x-wiki aaaa {{#invoke:pages|get_current_section}} == یەکەم == {{#invoke:pages|get_current_section}} === بەش === {{#invoke:pages|get_current_section}} == دووەم == {{#invoke:pages|get_current_section}} === بەش === {{#invoke:pages|get_current_section}} benmaua1ki5s8ai2gjecl8654nlcmt2 36923 36922 2026-08-17T23:09:36Z Ghybu 12 36923 wikitext text/x-wiki ## aaa {{#invoke:Pages|test}} ## bbb {{#invoke:Pages|test}} 4poy65x1r4jquqyssdk22m02jh7iszb 36924 36923 2026-08-17T23:09:52Z Ghybu 12 36924 wikitext text/x-wiki ## aaa {{#invoke:pages|test}} ## bbb {{#invoke:pages|test}} pma3fm2vescxnhoctg2g62dmirhrdch 36925 36924 2026-08-17T23:22:52Z Ghybu 12 36925 wikitext text/x-wiki == French == {{#invoke:pages|test}} === Noun === {{#invoke:pages|test}} == English == {{#invoke:pages|test}} === Noun === {{#invoke:pages|test}} 4a5tllie89ffggu43c2ynyykzezq0v8 36928 36925 2026-08-17T23:46:47Z Ghybu 12 پەڕەکەی واڵا کردەوە 36928 wikitext text/x-wiki phoiac9h4m842xq45sp7s6u21eteeq1 بەکارھێنەر:Ghybu/test2 2 11483 36926 2026-08-17T23:30:42Z Ghybu 12 ... 36926 wikitext text/x-wiki do local current_section function export.get_current_section() if current_section ~= nil then return current_section end local frame = parent_frame or get_parent_frame() while frame do if find(frame:getTitle(), "^Module:") then current_section = 0 return 0 end frame = frame:getParent() end local current = current_frame or get_current_frame() local extension_tag = current.extensionTag -- CKB: an empty nowiki does not produce a marker. -- Therefore, we give it some content. local nowiki_marker = extension_tag( current, "nowiki", "CKBSEC" ) -- Generate an artificial heading and retrieve its number. local h = tonumber(match( current:preprocess("=" .. nowiki_marker .. "="), "\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127" )) if not h then current_section = 0 return 0 end -- Retrieve the number of the nowiki marker. local n, offset = tonumber(match( nowiki_marker, "\127'\"`UNIQ%-%-nowiki%-([%dA-F]+)%-QINU`\"'\127" ), 16) -- Search for the offset in previous markers. while not offset and n > 0 do n = n - 1 offset = match( unstrip_nowiki( format( "\127'\"`UNIQ--nowiki-%08X-QINU`\"'\127", n ) ), "^CKBSEC\1(%d+)" ) end offset = offset and tonumber(offset) or 0 -- Store the offset. extension_tag( current, "nowiki", "CKBSEC\1" .. offset ) -- On ckb, the first generated heading is h = 0. -- MediaWiki sections start at 1. current_section = h - offset + 1 return current_section end get_current_section = export.get_current_section end 9jnkvyt0bkj8zmru7ga7c3nbgmx7cum 36927 36926 2026-08-17T23:46:33Z Ghybu 12 پەڕەکەی واڵا کردەوە 36927 wikitext text/x-wiki phoiac9h4m842xq45sp7s6u21eteeq1 پۆل:ناوەکان بەپێی زمان 14 11484 36934 2026-08-18T00:30:29Z Ghybu 12 پەڕەی دروست کرد بە «{{auto cat}}»ەوە 36934 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx پۆل:Pages using catfix 14 11485 36935 2026-08-18T00:36:47Z Ghybu 12 پەڕەی دروست کرد بە «{{auto cat}}»ەوە 36935 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx پۆل:لێما 14 11486 36936 2026-08-18T01:02:34Z Ghybu 12 پەڕەی دروست کرد بە «{{auto cat}}»ەوە 36936 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx 36937 36936 2026-08-18T01:11:05Z Ghybu 12 36937 wikitext text/x-wiki {{delete}} 35r2j9t4ectnt1cmb7mlgcqvwz6h5k6 پۆل:لێماکان بەپێی زمان 14 11487 36938 2026-08-18T01:12:11Z Ghybu 12 پەڕەی دروست کرد بە «{{cat bike}}»ەوە 36938 wikitext text/x-wiki {{cat bike}} 9n8zc4l476sseevvv6gc4tgsxplgezt 36939 36938 2026-08-18T01:12:30Z Ghybu 12 36939 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx پۆل:ھاوەڵناوەکان بەپێی زمان 14 11488 36945 2026-08-18T02:01:59Z Ghybu 12 پەڕەی دروست کرد بە «{{auto cat}}»ەوە 36945 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx پۆل:کارەکان بەپێی زمان 14 11489 36946 2026-08-18T02:02:25Z Ghybu 12 پەڕەی دروست کرد بە «{{auto cat}}»ەوە 36946 wikitext text/x-wiki {{auto cat}} eomzlm5v4j7ond1phrju7cnue91g5qx