ဝိက်ရှေန်နရဳ mnwwiktionary https://mnw.wiktionary.org/wiki/%E1%80%9D%E1%80%AD%E1%80%80%E1%80%BA%E1%80%9B%E1%80%BE%E1%80%B1%E1%80%94%E1%80%BA%E1%80%94%E1%80%9B%E1%80%B3:%E1%80%99%E1%80%AF%E1%80%80%E1%80%BA%E1%80%9C%E1%80%AD%E1%80%80%E1%80%BA%E1%80%90%E1%80%99%E1%80%BA MediaWiki 1.47.0-wmf.5 case-sensitive မဳဒဳယာ တၟေင် ဓရီုကျာ ညးလွပ် ညးလွပ် ဓရီုကျာ ဝိက်ရှေန်နရဳ ဝိက်ရှေန်နရဳ ဓရီုကျာ ဝှာင် ဝှာင် ဓရီုကျာ မဳဒဳယာဝဳကဳ မဳဒဳယာဝဳကဳ ဓရီုကျာ ထာမ်ပလိက် ထာမ်ပလိက် ဓရီုကျာ ရီု ရီု ဓရီုကျာ ကဏ္ဍ ကဏ္ဍ ဓရီုကျာ အဆက်လက္ကရဴ အဆက်လက္ကရဴ ဓရီုကျာ ကာရန် ကာရန် ဓရီုကျာ အဘိဓာန် အဘိဓာန် ဓရီုကျာ ဗီုပြၚ်သိုၚ်တၟိ ဗီုပြၚ်သိုၚ်တၟိ ဓရီုကျာ TimedText TimedText talk မဝ်ဂျူ မဝ်ဂျူ ဓရီုကျာ Event Event talk မဝ်ဂျူ:table/doc 828 650 396276 142345 2026-06-04T04:21:39Z 咽頭べさ 33 396276 wikitext text/x-wiki This module provides functions for dealing with Lua tables. All of them, except for two helper functions, take a table as their first argument. Some functions are available as methods in the arrays created by [[Module:array]]. Functions by what they do: * Create a new table: ** {{#invoke:string|gsub|shallowCopy, deepCopy, removeDuplicates, numKeys, compressSparseArray, keysToList, reverse, invert, listToSet|%a+|3=<code class="n">%1</code>}} * Create an array: ** {{#invoke:string|gsub|removeDuplicates, numKeys, compressSparseArray, keysToList, reverse|%a+|3=<code class="n">%1</code>}} * Return information about the table: ** {{#invoke:string|gsub|size, length, contains, keyFor, isArray, deepEquals|%a+|3=<code class="n">%1</code>}} * Treat the table as an array (that is, operate on the values in the array portion of the table: values indexed by consecutive integers starting at {{code|lua|1}}): ** {{#invoke:string|gsub|removeDuplicates, length, contains, serialCommaJoin, reverseIpairs, reverse, invert, listToSet, isArray|%a+|3=<code class="n">%1</code>}} * Treat a table as a sparse array (that is, operate on values indexed by non-consecutive integers): ** {{#invoke:string|gsub|numKeys, maxIndex, compressSparseArray, sparseConcat, sparseIpairs|%a+|3=<code class="n">%1</code>}} * Generate an iterator: ** {{#invoke:string|gsub|sparseIpairs, sortedPairs, reverseIpairs|%a+|3=<code class="n">%1</code>}} * Other: ** {{#invoke:string|gsub|sparseConcat, serialCommaJoin, reverseConcat|%a+|3=<code class="n">%1</code>}} The original version was a copy of {{w|Module:TableTools}} on Wikipedia via [[c:Module:TableTools|Module:TableTools]] on Commons, but new functions have been added since then. ==Detailed documentation== {{module documentation|section_level=3|identifier=^export}} {{module cat|-|အရာမပကောံဂွံလဝ်}} m94lcaeo8i7g7sixgocwsxltsc9injb 396277 396276 2026-06-04T04:22:45Z 咽頭べさ 33 အကြောင်းအရာ "{{module documentation|section_level=3|identifier=^export}} {{module cat|-|အရာမပကောံဂွံလဝ်}}" ဖြင့် အစားထိုးခဲ့သည် 396277 wikitext text/x-wiki {{module documentation|section_level=3|identifier=^export}} {{module cat|-|အရာမပကောံဂွံလဝ်}} 11gra5jrzw20amymjp4ciuguhlfs8ga မဝ်ဂျူ:la-nominal 828 6716 396230 370983 2026-06-03T15:06:29Z 咽頭べさ 33 396230 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "ပဌမ", ["1&2"] = "ပဌမ ကဵု ဒုတိယ", ["2"] = "ဒုတိယ", ["3"] = "တတိယ", ["4"] = "စတုတ္ထ", ["5"] = "ပဉ္စမ", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "နာမဝိသေသန", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. "portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. "different stems" ) end local subtitle_portion = concat(subtitle_portions, ";") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("ပါ်ပါဲထောံဟွံမာန်") .. "အၚ်္ဂ") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|မလဟုတ်စှ်ေအလန်ပဌမ]]") declensions_title = declensions_title:gsub("<1&2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|ပဌမ]]/[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<3>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်တတိယ|မလဟုတ်စှ်ေအလန်တတိယ]]") declensions_title = declensions_title:gsub("<4>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်စတုတ္ထ|မလဟုတ်စှ်ေအလန်စတုတ္ထ]]") declensions_title = declensions_title:gsub("<5>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဉ္စမ|မလဟုတ်စှ်ေအလန်ပဉ္စမ]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ",မနွံကဵုခၞံဗဒှ်လဝ်") end if parsed_run.num == "sg" then insert(post_text_parts, ",ပါဲနူကိုန်ဨကဝုစ်") elseif parsed_run.num == "pl" then insert(post_text_parts, ",ပါဲနူကိုန်ဗဟုဝစ်") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "。" end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "ပတုပ်ရံၚ်" or degree == "သဒ္ဒာ" then params.positive = sublist end if degree ~= "ပတုပ်ရံၚ်" then params.comp = sublist end if degree ~= "သဒ္ဒာ" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms("နာမ်", parent_args) if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "နာမဝိသေသန") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export 41zoz497bw2mhzvwjln7zwcbvtjq2hw 396231 396230 2026-06-03T15:07:06Z 咽頭べさ 33 ကလေင်ပလီု မူတၟိ[[Special:Diff/396230|396230]]နကု[[Special:Contributions/咽頭べさ|咽頭べさ]] ([[User talk:咽頭べさ|ဓရီုကျာ]]) 396231 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "ပဌမ", ["1&2"] = "ပဌမ ကဵု ဒုတိယ", ["2"] = "ဒုတိယ", ["3"] = "တတိယ", ["4"] = "စတုတ္ထ", ["5"] = "ပဉ္စမ", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "နာမဝိသေသန", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. "portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. "different stems" ) end local subtitle_portion = concat(subtitle_portions, ";") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("ပါ်ပါဲထောံဟွံမာန်") .. "အၚ်္ဂ") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|မလဟုတ်စှ်ေအလန်ပဌမ]]") declensions_title = declensions_title:gsub("<1&2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|ပဌမ]]/[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<3>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်တတိယ|မလဟုတ်စှ်ေအလန်တတိယ]]") declensions_title = declensions_title:gsub("<4>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်စတုတ္ထ|မလဟုတ်စှ်ေအလန်စတုတ္ထ]]") declensions_title = declensions_title:gsub("<5>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဉ္စမ|မလဟုတ်စှ်ေအလန်ပဉ္စမ]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ",မနွံကဵုခၞံဗဒှ်လဝ်") end if parsed_run.num == "sg" then insert(post_text_parts, ",ပါဲနူကိုန်ဨကဝုစ်") elseif parsed_run.num == "pl" then insert(post_text_parts, ",ပါဲနူကိုန်ဗဟုဝစ်") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "。" end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "ပတုပ်ရံၚ်" or degree == "သဒ္ဒာ" then params.positive = sublist end if degree ~= "ပတုပ်ရံၚ်" then params.comp = sublist end if degree ~= "သဒ္ဒာ" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "နာမ်") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "နာမဝိသေသန") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export iknzf3ysrj4ds8oqkjf21wutgeg7t9z 396232 396231 2026-06-03T15:44:01Z 咽頭べさ 33 396232 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "ပဌမ", ["1&2"] = "ပဌမ ကဵု ဒုတိယ", ["2"] = "ဒုတိယ", ["3"] = "တတိယ", ["4"] = "စတုတ္ထ", ["5"] = "ပဉ္စမ", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "နာမဝိသေသန", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. "portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. "different stems" ) end local subtitle_portion = concat(subtitle_portions, ";") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("ပါ်ပါဲထောံဟွံမာန်") .. "အၚ်္ဂ") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|မလဟုတ်စှ်ေအလန်ပဌမ]]") declensions_title = declensions_title:gsub("<1&2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|ပဌမ]]/[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<3>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်တတိယ|မလဟုတ်စှ်ေအလန်တတိယ]]") declensions_title = declensions_title:gsub("<4>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်စတုတ္ထ|မလဟုတ်စှ်ေအလန်စတုတ္ထ]]") declensions_title = declensions_title:gsub("<5>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဉ္စမ|မလဟုတ်စှ်ေအလန်ပဉ္စမ]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("$%။", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ",မနွံကဵုခၞံဗဒှ်လဝ်") end if parsed_run.num == "sg" then insert(post_text_parts, ",ပါဲနူကိုန်ဨကဝုစ်") elseif parsed_run.num == "pl" then insert(post_text_parts, ",ပါဲနူကိုန်ဗဟုဝစ်") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = ucfirst(declensions_title) .. post_text .. "。" end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "ပတုပ်ရံၚ်" or degree == "သဒ္ဒာ" then params.positive = sublist end if degree ~= "ပတုပ်ရံၚ်" then params.comp = sublist end if degree ~= "သဒ္ဒာ" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "နာမ်") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "နာမဝိသေသန") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export gttr97u93itjzwxxiwc8ugtjuzaen4z 396233 396232 2026-06-03T15:46:39Z 咽頭べさ 33 ကလေင်ပလီု မူတၟိ[[Special:Diff/396232|396232]]နကု[[Special:Contributions/咽頭べさ|咽頭べさ]] ([[User talk:咽頭べさ|ဓရီုကျာ]]) 396233 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "ပဌမ", ["1&2"] = "ပဌမ ကဵု ဒုတိယ", ["2"] = "ဒုတိယ", ["3"] = "တတိယ", ["4"] = "စတုတ္ထ", ["5"] = "ပဉ္စမ", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "နာမဝိသေသန", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. "portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. "different stems" ) end local subtitle_portion = concat(subtitle_portions, ";") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("ပါ်ပါဲထောံဟွံမာန်") .. "အၚ်္ဂ") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|မလဟုတ်စှ်ေအလန်ပဌမ]]") declensions_title = declensions_title:gsub("<1&2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|ပဌမ]]/[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<3>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်တတိယ|မလဟုတ်စှ်ေအလန်တတိယ]]") declensions_title = declensions_title:gsub("<4>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်စတုတ္ထ|မလဟုတ်စှ်ေအလန်စတုတ္ထ]]") declensions_title = declensions_title:gsub("<5>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဉ္စမ|မလဟုတ်စှ်ေအလန်ပဉ္စမ]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ",မနွံကဵုခၞံဗဒှ်လဝ်") end if parsed_run.num == "sg" then insert(post_text_parts, ",ပါဲနူကိုန်ဨကဝုစ်") elseif parsed_run.num == "pl" then insert(post_text_parts, ",ပါဲနူကိုန်ဗဟုဝစ်") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = lcfirst(declensions_title) .. post_text else declensions_title = post_text .. ucfirst(declensions_title) .. "။" end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "ပတုပ်ရံၚ်" or degree == "သဒ္ဒာ" then params.positive = sublist end if degree ~= "ပတုပ်ရံၚ်" then params.comp = sublist end if degree ~= "သဒ္ဒာ" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "နာမ်") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "နာမဝိသေသန") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export qgubzsgf79fxj89i2pro67iwkrv6cw3 396234 396233 2026-06-03T15:49:43Z 咽頭べさ 33 396234 Scribunto text/plain local export = {} --[=[ Authorship: Ben Wing <benwing2>, with many ideas and a little code coming from the old [[Module:la-decl-multi]] by KC Kenny Lau. ]=] -- TODO: -- (DONE) Eliminate specification of noteindex from la-adj/data -- (DONE?) Finish autodetection of adjectives -- (DONE) Remove old noun code -- (DONE) Implement <.sufn> -- (DONE) Look into adj voc=false -- (DONE) Handle loc in adjectives -- Error on bad subtypes -- Make sure Google Books link still works. -- (DONE) Make sure .sufn triggers insertion of 'with m optionally -> n in compounds' in title. -- (DONE) Make sure title returned to la-adj lowercases the first letter even with a custom title. --[=[ TERMINOLOGY: -- "slot" = A particular case/number combination (for nouns) or case/number/gender combination (for adjectives). Example slot names are "abl_sg" (for noun) or "acc_pl_f" (for adjectives). Each slot is filled with zero or more forms. -- "form" = The declined Latin form representing the value of a given slot. For example, rēge is a form, representing the value of the abl_sg slot of the lemma rēx. -- "lemma" = The dictionary form of a given Latin term. For nouns, it's generally the nominative singular, but will be the nominative plural of plurale tantum nouns (e.g. [[castra]]), and may occasionally be another form (e.g. the genitive singular) if the nominative singular is missing. For adjectives, it's generally the masculine nominative singular, but will be the masculine nominative plural of plurale tantum adjectives (e.g. [[dēnī]]). -- "plurale tantum" (plural "pluralia tantum") = A noun or adjective that exists only in the plural. Examples are castra "army camp", faucēs "throat", and dēnī "ten each" (used for counting pluralia tantum nouns). -- "singulare tantum" (plural "singularia tantum") = A noun or adjective that exists only in the singular. Examples are geōlogia "geology" (and in general most non-count nouns) and the adjective ūnus "one". ]=] local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local headword_data_module = "Module:headword/data" local json_module = "Module:JSON" local la_adj_data_module = "Module:la-adj/data" local la_adj_table_module = "Module:la-adj/table" local la_noun_data_module = "Module:la-noun/data" local la_noun_table_module = "Module:la-noun/table" local la_utilities_module = "Module:la-utilities" local languages_module = "Module:languages" local links_module = "Module:links" local load_module = "Module:load" local parameters_module = "Module:parameters" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local concat = table.concat local insert = table.insert local iter_adj_slots -- defined below local iter_noun_slots -- defined below local umatch = mw.ustring.match local function add_indefinite_article(...) add_indefinite_article = require(en_utilities_module).add_indefinite_article return add_indefinite_article(...) end local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function deep_copy(...) deep_copy = require(table_module).deepCopy return deep_copy(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function full_link(...) full_link = require(links_module).full_link return full_link(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function lcfirst(...) lcfirst = require(string_utilities_module).lcfirst return lcfirst(...) end local function load_data(...) load_data = require(load_module).load_data return load_data(...) end local function make_adj_table(...) make_adj_table = require(la_adj_table_module).make_table return make_adj_table(...) end local function make_noun_table(...) make_noun_table = require(la_noun_table_module).make_table return make_noun_table(...) end local function make_noun_table_sg(...) make_noun_table_sg = require(la_noun_table_module).make_table_sg return make_noun_table_sg(...) end local function make_noun_table_pl(...) make_noun_table_pl = require(la_noun_table_module).make_table_pl return make_noun_table_pl(...) end local function make_stem2(...) make_stem2 = require(la_utilities_module).make_stem2 return make_stem2(...) end local function normalize_form(...) normalize_form = require(la_utilities_module).normalize_form return normalize_form(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function singularize(...) singularize = require(en_utilities_module).singularize return singularize(...) end local function split(...) split = require(string_utilities_module).split return split(...) end local function ucfirst(...) ucfirst = require(string_utilities_module).ucfirst return ucfirst(...) end local m_adj_decl local function get_m_adj_decl() m_adj_decl, get_m_adj_decl = require(la_adj_data_module), nil return m_adj_decl end local m_noun_decl local function get_m_noun_decl() m_noun_decl, get_m_noun_decl = require(la_noun_data_module), nil return m_noun_decl end local lang local function get_lang() lang, get_lang = require(languages_module).getByCode("la") return lang end local namespace local function get_namespace() namespace, get_namespace = load_data(headword_data_module).page.namespace, nil return namespace end local pagename local function get_pagename() pagename, get_pagename = load_data(headword_data_module).pagename, nil return pagename end local ligatures = { ['Ae'] = 'Æ', ['ae'] = 'æ', ['Oe'] = 'Œ', ['oe'] = 'œ', } local cases = { "nom", "gen", "acc", "dat", "abl", "voc", "loc" } local cases_n = #cases local nums = { "sg", "pl" } local nums_n = #nums local genders = { "m", "f", "n" } local genders_n = #genders local declension_to_english = setmetatable({ ["1"] = "ပဌမ", ["1&2"] = "ပဌမ ကဵု ဒုတိယ", ["2"] = "ဒုတိယ", ["3"] = "တတိယ", ["4"] = "စတုတ္ထ", ["5"] = "ပဉ္စမ", }, { __index = function(t, k) return rawget(t, k:match("^[^+-]*")) end }) local number_to_english = { "one", "two", "three", "four", "five" } local linked_prefixes = { "", "linked_" } function export.iter_potential_noun_lemma_slots() local num, case = 1, 0 return function() case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end return cases[case] .. "_" .. nums[num] end end local potential_noun_lemma_slots = {} for slot in export.iter_potential_noun_lemma_slots() do insert(potential_noun_lemma_slots, slot) end local linked_to_non_linked_noun_slots = {} for _, slot in ipairs(potential_noun_lemma_slots) do linked_to_non_linked_noun_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with a noun declension, where a slot -- is a particular case/number combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg, linked_nom_pl), which aren't overridable. function export.iter_noun_slots(overridable_only) local case, num, linked_variant = 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] end end iter_noun_slots = export.iter_noun_slots function export.iter_potential_adj_lemma_slots() local num, case, gen = 1, 1, 0 return function() gen = gen + 1 if gen > genders_n then gen = 1 case = case + 1 if case > 3 then case = 1 num = num + 1 if num > nums_n then return nil end end end return cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end -- List of adjective slots for which we generate linked variants. Include -- feminine and neuter variants because they will be needed if the adjective -- is part of a multiword feminine or neuter noun. local potential_adj_lemma_slots = {} for slot in export.iter_potential_adj_lemma_slots() do insert(potential_adj_lemma_slots, slot) end local linked_to_non_linked_adj_slots = {} for _, slot in ipairs(potential_adj_lemma_slots) do linked_to_non_linked_adj_slots["linked_" .. slot] = slot end -- Iterate over all the "slots" associated with an adjective declension, where a slot -- is a particular case/number/gender combination. If overridable_only, don't include the -- "linked_" variants (linked_nom_sg_m, linked_nom_pl_m, etc.), which aren't overridable. function export.iter_adj_slots(overridable_only) local case, num, gen, linked_variant = 1, 1, 1, 0 return function() linked_variant = linked_variant + 1 local max_linked_variant = (overridable_only or case > 3) and 1 or 2 if linked_variant > max_linked_variant then linked_variant = 1 gen = gen + 1 if gen > genders_n then gen = 1 num = num + 1 if num > nums_n then num = 1 case = case + 1 if case > cases_n then return nil end end end end return linked_prefixes[linked_variant] .. cases[case] .. "_" .. nums[num] .. "_" .. genders[gen] end end iter_adj_slots = export.iter_adj_slots -- Iterate over all the "slots" associated with a noun or adjective declension (depending on -- the value of IS_ADJ), where a slot is a particular case/number combination (in the case of -- nouns) or case/number/gender combination (in the case of adjectives). If OVERRIDABLE_ONLY -- is specified, only include overridable slots (not including linked_ variants). local function iter_slots(is_adj, overridable_only) if is_adj then return iter_adj_slots(overridable_only) end return iter_noun_slots(overridable_only) end local function concat_forms_in_slot(forms) if forms and forms ~= "" and forms ~= "—" and #forms > 0 then local new_vals = {} for _, v in ipairs(forms) do insert(new_vals, (v:gsub("|", "<!>"))) end return concat(new_vals, ",") end end local function glossary_link(anchor, text) text = text or anchor return "[[Appendix:Glossary#" .. anchor .. "|" .. text .. "]]" end local function track(page) debug_track("la-nominal/" .. page) return true end local function set_union(sets) local union = {} for _, set in ipairs(sets) do for key, _ in pairs(set) do union[key] = true end end return union end local function set_difference(set1, set2) local diff = {} for key, _ in pairs(set1) do if not set2[key] then diff[key] = true end end return diff end -- If a form is set as '*', that means it is unattested -- but should still be generated -- TODO: handle asterisks in forms stored in the data local function unattested_forms(data, args, is_adj) for slot in iter_slots(is_adj) do local arg = args[slot] if arg ~= nil then arg = arg:match("^*(.*)") if arg then data.unattested[slot] = true args[slot] = arg ~= "" and arg or nil end end end end -- Make a link only if the form is attested local function link_if_attested(form, accel, is_unattested) local data = {lang = lang or get_lang()} if is_unattested then data.alt = "*" .. form else data.term = form data.accel = accel end return full_link(data) end local function process_form(slot, data, args, linked_to_non_linked) local forms = data.forms -- If nomf=1 passed, clear out all masculine and feminine forms. if data.nomf and slot:match("%f[^%z_][mf]%f[%z_]") then forms[slot] = nil end -- If noneut=1 passed, clear out all neuter forms. if data.noneut and slot:match("%f[^%z_]n%f[%z_]") then forms[slot] = nil end local val if args[slot] then val = args[slot] data.user_specified[slot] = true else -- Overridding nom_sg/nom_sg_m etc. should override linked_nom_sg -- so that the correct value gets displayed in the headword, which -- uses linked_nom_sg. local non_linked_equiv_slot = linked_to_non_linked[slot] if non_linked_equiv_slot and args[non_linked_equiv_slot] then val = args[non_linked_equiv_slot] data.user_specified[slot] = true else val = forms[slot] end end if val then if type(val) == "string" then val = split(val, "/", true, true) end local num = data.num if ( (num == "pl" and slot:find("sg", nil, true)) or (num == "sg" and slot:find("pl", nil, true)) ) then forms[slot] = nil elseif val[1] == "" or val[1] == "-" or val[1] == "—" then forms[slot] = "—" if val[2] then error("Cannot specify additional forms for " .. slot .. ' if it has been cancelled with "-"') end else forms[slot] = val end end end local function process_noun_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args); -- Process overrides and canonicalize forms. for slot in iter_noun_slots() do process_form(slot, data, args, linked_to_non_linked_noun_slots) end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num] else accel_lemma = data.forms["nom_sg"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_noun_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]$", "|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end local function process_adj_forms_and_overrides(data, args, generate_type) local redlink = false unattested_forms(data, args, true) -- Process overrides and canonicalize forms. for slot in iter_adj_slots() do process_form(slot, data, args, linked_to_non_linked_adj_slots) end -- See if the masculine and feminine/neuter are the same across all slots. -- If so, blank out the feminine/neuter so we use a table that combines -- masculine and feminine, or masculine/feminine/neuter. for _, gender in ipairs({"f", "n"}) do local other_is_masc = true for _, case in ipairs(cases) do for _, num in ipairs(nums) do if not deep_equals(data.forms[case .. "_" .. num .. "_" .. gender], data.forms[case .. "_" .. num .. "_m"]) then other_is_masc = false break end end if not other_is_masc then break end end if other_is_masc then for _, case in ipairs(cases) do for _, num in ipairs(nums) do data.forms[case .. "_" .. num .. "_" .. gender] = nil end end end end -- No accel forms or red link checking if generate_type == "bare". if generate_type == "bare" then return end -- Compute the lemma for accelerators. Do this after processing -- overrides in case we overrode the lemma form(s). local accel_lemma, accel_lemma_f if data.num and data.num ~= "" then accel_lemma = data.forms["nom_" .. data.num .. "_m"] accel_lemma_f = data.forms["nom_" .. data.num .. "_f"] else accel_lemma = data.forms["nom_sg_m"] accel_lemma_f = data.forms["nom_sg_f"] end if type(accel_lemma) == "table" then accel_lemma = accel_lemma[1] end if type(accel_lemma_f) == "table" then accel_lemma_f = accel_lemma_f[1] end -- Set the accelerators, and determine if there are red links. for slot in iter_adj_slots() do local val = data.forms[slot] if val and val ~= "" and val ~= "—" and #val > 0 then for _, form in ipairs(val) do local accel_form = slot accel_form = accel_form:gsub("_([sp])[gl]_", "|%1|") if data.noneut then -- If noneut=1, we're being asked to do a noun like -- Aquītānus or Rōmānus that has masculine and feminine -- variants, not an adjective. In that case, make the -- accelerators correspond to nominal case/number forms -- without the gender, and use the feminine as the -- lemma for feminine forms. if slot:find("_f", nil, true) then data.accel[slot] = {form = accel_form:gsub("|f$", ""), lemma = accel_lemma_f} else data.accel[slot] = {form = accel_form:gsub("|m$", ""), lemma = accel_lemma} end else if not data.forms.nom_sg_n and not data.forms.nom_pl_n then -- use multipart tags if called for accel_form = accel_form:gsub("|m$", "|m//f//n") elseif not data.forms.nom_sg_f and not data.forms.nom_pl_f then accel_form = accel_form:gsub("|m$", "|m//f") end -- use the order nom|m|s, which is more standard than nom|s|m accel_form = accel_form:gsub("|(.-)|(.-)$", "|%2|%1") data.accel[slot] = {form = accel_form, lemma = accel_lemma} end if not redlink and namespace == "" then local title = ((lang or get_lang()):makeEntryName(form)) local t = mw.title.new(title) if t and not t.exists then -- insert(data.categories, "Latin " .. data.pos .. " with red links in their inflection tables") redlink = true end end end end end end -- Convert data.forms[slot] for all slots into displayable text. This is -- an older function, still currently used for nouns but not for adjectives. -- For adjectives, the adjective table module has special code to combine -- adjacent slots, and needs the original forms plus other text that will -- go into the displayable text for the slot; this is handled below by -- partial_show_forms() and finish_show_form(). local function show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} for slot in iter_slots(is_adj) do local val = data.forms[slot] if val and val ~= "" and val ~= "—" then for i, form in ipairs(val) do local link = link_if_attested(form, data.accel[slot], data.unattested[slot]) local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end val[i] = link .. '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>' else val[i] = link end end -- FIXME, do we want this difference? data.forms[slot] = concat(val, is_adj and ", " or "<br />") end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Generate the display form for a set of slots with identical content. We -- verify that the slots are actually identical, and throw an assertion error -- if not. The display form is as in show_forms() but combines together all the -- accelerator forms for all the slots. local function finish_show_form(data, slots, is_adj) assert(#slots > 0) local slot1 = slots[1] local forms = data.forms[slot1] local notetext = data.notetext[slot1] for _, slot in ipairs(slots) do if not deep_equals(data.forms[slot], forms) then error("data.forms[" .. slot1 .. "] = " .. (concat_forms_in_slot(forms) or "nil") .. ", but data.forms[" .. slot .. "] = " .. (concat_forms_in_slot(data.forms[slot]) or "nil")) end assert(deep_equals(data.notetext[slot], notetext)) end if not forms then return "—" else local accel_forms = {} local accel_lemma = data.accel[slot1].lemma for _, slot in ipairs(slots) do assert(data.accel[slot].lemma == accel_lemma) insert(accel_forms, data.accel[slot].form) end local combined_accel_form = concat(accel_forms, "|;|") local accel = {form = combined_accel_form, lemma = accel_lemma} local formtext = {} for i, form in ipairs(forms) do insert(formtext, link_if_attested(form, accel, data.unattested[slot1]) .. notetext[i]) end -- FIXME, do we want this difference? return concat(formtext, is_adj and ", " or "<br />") end end -- Used by the adjective table module. This does some of the work of -- show_forms(); in particular, it converts all empty forms of any format -- (nil, "", "—") to nil and, if the forms aren't empty, generates the footnote -- text associated with each form. local function partial_show_forms(data, is_adj) local noteindex = 1 local notes = {} local seen_notes = {} data.notetext = {} -- Store this function in DATA so that it can be called from the adjective -- table module without needing to require this module, which will (or -- could) lead to recursive module requiring. data.finish_show_form = finish_show_form for slot in iter_slots(is_adj) do local val = data.forms[slot] if not val or val == "" or val == "—" then data.forms[slot] = nil else local notetext = {} for i in ipairs(val) do local this_notes = data.notes[slot .. i] if this_notes and not data.user_specified[slot] then if type(this_notes) == "string" then this_notes = {this_notes} end local link_indices = {} for _, this_note in ipairs(this_notes) do local this_noteindex = seen_notes[this_note] if not this_noteindex then -- Generate a footnote index. this_noteindex = noteindex noteindex = noteindex + 1 insert(notes, '<sup style="color: red">' .. this_noteindex .. '</sup>' .. this_note) seen_notes[this_note] = this_noteindex end insert_if_not(link_indices, this_noteindex) end insert(notetext, '<sup style="color: red">' .. concat(link_indices, ",") .. '</sup>') else insert(notetext, "") end end data.notetext[slot] = notetext end end for _, footnote in ipairs(data.footnotes) do insert(notes, footnote) end data.footnotes = concat(notes, "<br />") end -- Given an ending (or possibly a full regex matching the entire lemma, if -- a regex group is present), return the base minus the ending, or nil if -- the ending doesn't match. local function extract_base(lemma, ending) if ending:find("(", nil, true) then return umatch(lemma, ending) end return umatch(lemma, "^(.*)" .. ending .. "$") end -- Given ENDINGS_AND_SUBTYPES (a list of pairs of endings with associated -- subtypes, where each pair consists of a single ending spec and a list of -- subtypes), check each ending in turn against LEMMA. If it matches, return -- the pair BASE, STEM2, SUBTYPES where BASE is the remainder of LEMMA minus -- the ending, STEM2 is as passed in, and SUBTYPES is the subtypes associated -- with the ending. But don't return SUBTYPES if any of the subtypes in the -- list is specifically canceled in SPECIFIED_SUBTYPES (a set, i.e. a table -- where the keys are strings and the value is always true); instead, consider -- the next ending in turn. If no endings match, throw an error if DECLTYPE is -- non-nil, mentioning the DECLTYPE (the user-specified declension); but if -- DECLTYPE is nil, just return nil, nil, nil. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". local function get_noun_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local subtypes = ending_and_subtypes[2] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. -- In addition, M or F as a subtype is canceled by N, and -- vice-versa, but M doesn't cancel F or vice-versa; instead, -- we simply ignore the conflicting gender specification when -- constructing the combination of specified and inferred subtypes. -- The reason for this is that neuters have distinct declensions -- from masculines and feminines, but masculines and feminines have -- the same declension, and various nouns in Latin that are -- normally masculine are exceptionally feminine and vice-versa -- (nauta, agricola, fraxinus, malus "apple tree", manus, rēs, -- etc.). -- -- In addition, sg as a subtype is canceled by pl and vice-versa. -- It's also possible to specify both, which will override sg but -- not cancel it (in the sense that it won't prevent the relevant -- rule from matching). For example, there's a rule specifying that -- lemmas beginning with a capital letter and ending in -ius take -- the ius.voci.sg subtypes. Specifying such a lemma with the -- subtype both will result in the ius.voci.both subtypes, whereas -- specifying such a lemma with the subtype pl will cause this rule -- not to match, and it will fall through to a less specific rule -- that returns just the ius subtype, which will be combined with -- the explicitly specified pl subtype to produce ius.pl. if specified_subtypes["-" .. subtype] or subtype == "N" and (specified_subtypes.M or specified_subtypes.F) or (subtype == "M" or subtype == "F") and specified_subtypes.N or subtype == "sg" and specified_subtypes.pl or subtype == "pl" and specified_subtypes.sg then not_this_subtype = true break end end end if not not_this_subtype then if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] local base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending == stem2 then return base, stem2, subtypes end else local base = extract_base(lemma, ending) if base then return base, stem2, subtypes end end end end if decltype then error("Unrecognized ending for declension-" .. decltype .. " noun: " .. lemma) end return nil, nil, nil end -- Autodetect the subtype of a noun given all the information specified by the -- user: lemma, stem2, declension type and specified subtypes. Three values are -- returned: the lemma base (i.e. the stem of the lemma, as required by the -- declension functions), the new stem2 and the autodetected subtypes. Note -- that this will not detect a given subtype if the explicitly specified -- subtypes are incompatible (i.e. if -SUBTYPE is specified for any subtype -- that would be returned; or if M or F is specified when N would be returned, -- and vice-versa; or if pl is specified when sg would be returned, and -- vice-versa). -- -- NOTE: This function has intimate knowledge of the way that the declension -- functions handle subtypes, particularly for the third declension. local function detect_noun_subtype(lemma, stem2, typ, subtypes) local base, _ if typ == "1" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ām", {"F", "am"}}, {"ās", {"M", "Greek", "Ma"}}, {"ēs", {"M", "Greek", "Me"}}, {"ē", {"F", "Greek"}}, {"ae", {"F", "pl"}}, {"a", {"F"}}, }) elseif typ == "2" then local detected_subtypes lemma, stem2, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*r)$", {"M", "er"}}, {"^(.*v)os$", {"M", "vos"}}, {"^(.*v)om$", {"N", "vom"}}, -- If the lemma ends in -os and the user said N or -M, then the -- following won't apply, and the second (neuter) -os will applly. {"os", {"M", "Greek"}}, {"os", {"N", "Greek", "us"}}, {"on", {"N", "Greek"}}, -- -ius beginning with a capital letter is assumed a proper name, -- and takes the voci subtype (vocative in -ī) along with the ius -- subtype and sg-only. Other nouns in -ius just take the ius -- subtype. Explicitly specify "sg" so that if .pl is given, -- this rule won't apply. {"^(%u.*)ius$", {"M", "ius", "voci", "sg"}}, {"ius", {"M", "ius"}}, {"ium", {"N", "ium"}}, -- If the lemma ends in -us and the user said N or -M, then the -- following won't apply, and the second (neuter) -us will applly. {"us", {"M"}}, {"us", {"N", "us"}}, {"um", {"N"}}, {"iī", {"M", "ius", "pl"}}, {"ia", {"N", "ium", "pl"}}, -- If the lemma ends in -ī and the user said N or -M, then the -- following won't apply, and the second (neuter) -ī will applly. {"ī", {"M", "pl"}}, {"ī", {"N", "us", "pl"}}, {"oe", {"M", "Greek", "pl"}}, {"a", {"N", "pl"}}, }) stem2 = stem2 or lemma return lemma, stem2, detected_subtypes elseif typ == "3" then if subtypes.pl then if subtypes.Greek then base = lemma:match("^(.*)erēs$") if base then return base .. "ēr", base .. "er", {"er"} end base = lemma:match("^(.*)ontēs$") if base then return base .. "ōn", base .. "ont", {"on"} end base = lemma:match("^(.*)es$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural Greek noun: " .. lemma) end base = lemma:match("^(.*)ia$") if base then return "foo", stem2 or base, {"N", "I", "pure"} end base = lemma:match("^(.*)a$") if base then return "foo", stem2 or base, {"N"} end base = lemma:match("^(.*)ēs$") if base then return "foo", stem2 or base, {} end error("Unrecognized ending for declension-3 plural noun: " .. lemma) end stem2 = stem2 or make_stem2(lemma) local detected_subtypes if subtypes.Greek then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"is", ""}, {"I"}}, {"ēr", {"er"}}, {"ōn", {"on"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} end if not subtypes.N then base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"^(%u.*pol)is$", ""}, {"F", "polis", "sg", "loc"}}, {{"tūdō", "tūdin"}, {"F"}}, {{"tās", "tāt"}, {"F"}}, {{"tūs", "tūt"}, {"F"}}, {{"tiō", "tiōn"}, {"F"}}, {{"siō", "siōn"}, {"F"}}, {{"xiō", "xiōn"}, {"F"}}, {{"gō", "gin"}, {"F"}}, {{"or", "ōr"}, {"M"}}, {{"tr[iī]x", "trīc"}, {"F"}}, {{"is", ""}, {"I"}}, {{"^(%l.*)ēs$", ""}, {"I"}}, }) if base then return lemma, stem2, detected_subtypes end end base, _, detected_subtypes = get_noun_subtype_by_ending(lemma, stem2, nil, subtypes, { {{"us", "or"}, {"N"}}, {{"us", "er"}, {"N"}}, {{"ma", "mat"}, {"N"}}, {{"men", "min"}, {"N"}}, {{"^(%u.*)e$", ""}, {"N", "sg"}}, {{"e", ""}, {"N", "I", "pure"}}, {{"al", "āl"}, {"N", "I", "pure"}}, {{"ar", "ār"}, {"N", "I", "pure"}}, }) if base then return lemma, stem2, detected_subtypes end return lemma, stem2, {} elseif typ == "4" then if subtypes.echo or subtypes.Callisto then base = lemma:match("^(.*)ō$") if not base then error("Declension-4 noun of subtype .echo or .Callisto should end in -ō: " .. lemma) end if subtypes.Callisto then return base, nil, {"F", "sg"} else return base, nil, {"F"} end end return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", {"M"}}, {"ū̆", {"N"}}, {"ūs", {"M", "pl"}}, {"ua", {"N", "pl"}}, }) elseif typ == "5" then return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"iēs", {"F", "i"}}, {"iēs", {"F", "i", "pl"}}, {"ēs", {"F"}}, {"ēs", {"F", "pl"}}, }) elseif typ == "sgpl" then return lemma, stem2, {} elseif typ == "irreg" and lemma == "domus" then -- [[domus]] auto-sets data.loc = true, but we need to know this -- before declining the noun so we can propagate it to other segments. return lemma, nil, {"loc"} elseif typ == "indecl" or typ == "irreg" and ( lemma == "Deus" or umatch(lemma, "^[IJ]ēs[uū]s$") or lemma == "Athōs" or lemma == "vēnum" ) then -- Indeclinable nouns, and certain irregular nouns, set data.num = "sg", -- but we need to know this before declining the noun so we can -- propagate it to other segments. return get_noun_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", {"both"}}, {"", {"sg"}}, {"", {"pl"}}, }) else return lemma, nil, {} end end -- Given ENDINGS_AND_SUBTYPES (a list of four-tuples of ENDING, RETTYPE, -- SUBTYPES, PROCESS_RETVAL), check each ENDING in turn against LEMMA and -- STEM2. If it matches, return a four-tuple BASE, STEM2, RETTYPE, NEW_SUBTYPES -- where BASE is normally the remainder of LEMMA minus the ending, STEM2 is -- as passed in, RETTYPE is as passed in, and NEW_SUBTYPES is the same as -- SUBTYPES minus any subtypes beginning with a hyphen. If no endings match, -- throw an error if DECLTYPPE is non-nil, mentioning the DECLTYPE -- (user-specified declension); but if DECLTYPE is nil, just return the tuple -- nil, nil, nil, nil. -- -- In order for a given entry to match, ENDING must match and also the subtypes -- in SUBTYPES (a list) must not be incompatible with the passed-in -- user-specified subtypes SPECIFIED_SUBTYPES (a set, i.e. a table where the -- keys are strings and the value is always true). "Incompatible" means that -- a given SUBTYPE is specified in either one and -SUBTYPE in the other, or -- that "pl" is found in SPECIFIED_SUBTYPES and not in SUBTYPES. -- -- The ending spec in ENDINGS_AND_SUBTYPES is one of the following: -- -- 1. A simple string, e.g. "tūdō", specifying an ending. -- 2. A regex that should match the entire lemma (it should be anchored at -- the beginning with ^ and at the end with $), and contains a single -- capturing group to match the base. -- 3. A pair {SIMPLE_STRING_OR_REGEX, STEM2_ENDING} where -- SIMPLE_STRING_OR_REGEX is one of the previous two possibilities and -- STEM2_ENDING is a string specifying the corresponding ending that must -- be present in STEM2. If this form is used, the combination of -- base + STEM2_ENDING must exactly match STEM2 in order for this entry -- to be considered a match. An example is {"is", ""}, which will match -- lemma == "follis", stem2 == "foll", but not lemma == "lapis", -- stem2 == "lapid". -- -- If PROCESS_STEM2 is given and the returned STEM2 would be nil, call -- process_stem2(BASE) to get the STEM2 to return. local function get_adj_type_and_subtype_by_ending(lemma, stem2, decltype, specified_subtypes, endings_and_subtypes, process_stem2) for _, ending_and_subtypes in ipairs(endings_and_subtypes) do local ending = ending_and_subtypes[1] local rettype = ending_and_subtypes[2] local subtypes = ending_and_subtypes[3] local process_retval = ending_and_subtypes[4] local not_this_subtype = false if ( specified_subtypes.pl and not contains(subtypes, "pl") or contains(subtypes, "both") and not specified_subtypes.both ) then -- We now require that plurale tantum terms specify a plural-form lemma. -- The autodetected subtypes will include 'pl' for such lemmas; if not, -- we fail this entry. Additionally, if the rule contains 'both', it -- must be explicitly specified to match. not_this_subtype = true else for _, subtype in ipairs(subtypes) do -- A subtype is directly canceled by specifying -SUBTYPE. if specified_subtypes["-" .. subtype] then not_this_subtype = true break end -- A subtype is canceled if the user specified SUBTYPE and -- -SUBTYPE is given in the to-be-returned subtypes. local must_not_be_present = subtype:match("^%-(.*)$") if must_not_be_present and specified_subtypes[must_not_be_present] then not_this_subtype = true break end end end if not not_this_subtype then local base if type(ending) == "table" then local lemma_ending = ending[1] local stem2_ending = ending[2] base = extract_base(lemma, lemma_ending) if base and base .. stem2_ending ~= stem2 then base = nil end else base = extract_base(lemma, ending) end if base then -- Remove subtypes of the form -SUBTYPE from the subtypes -- to be returned. local new_subtypes = {} for _, subtype in ipairs(subtypes) do if subtype:sub(1, 1) ~= "-" then insert(new_subtypes, subtype) end end if process_retval then base, stem2 = process_retval(base, stem2) end if process_stem2 then stem2 = stem2 or process_stem2(base) end return base, stem2, rettype, new_subtypes end end end if not decltype then return nil, nil, nil, nil elseif decltype == "" then error("Unrecognized ending for adjective: " .. lemma) else error("Unrecognized ending for declension-" .. decltype .. " adjective: " .. lemma) end end -- Autodetect the type and subtype of an adjective given all the information -- specified by the user: lemma, stem2, declension type and specified subtypes. -- Four values are returned: the lemma base (i.e. the stem of the lemma, as -- required by the declension functions), the value of stem2 to pass to the -- declension function, the declension type and the autodetected subtypes. -- Note that this will not detect a given subtype if -SUBTYPE is specified for -- any subtype that would be returned, or if SUBTYPE is specified and -SUBTYPE -- is among the subtypes that would be returned (such subtypes are filtered out -- of the returned subtypes). local function detect_adj_type_and_subtype(lemma, stem2, typ, subtypes) -- FIXME: not clear why "foo" is in production code. local function base_as_stem2(base, stem2) return "foo", base end local function constant_base(baseval) return function(base, stem2) return baseval, nil end end local function decl12_stem2(base) return base end local function decl3_stem2(base) return make_stem2(base) end local decl12_entries = { {"us", "1&2+", {}}, {"a", "1&2+", {}}, {"um", "1&2+", {}}, {"ī", "1&2+", {"pl"}}, {"ae", "1&2+", {"pl"}}, {"a", "1&2+", {"pl"}}, -- Nearly all -os adjectives are greekA {"os", "1&2+", {"greekA", "-greekE"}}, {"os", "1&2+", {"greekE", "-greekA"}}, {"ē", "1&2+", {"greekE", "-greekA"}}, {"on", "1&2+", {"greekA", "-greekE"}}, {"on", "1&2+", {"greekE", "-greekA"}}, {"^(.*er)$", "1&2+", {"er"}}, {"^(.*ur)$", "1&2+", {"er"}}, {"^(h)ic$", "1&2+", {"ic"}}, } local decl3_entries = { {"^(.*er)$", "3-3+", {}}, {"is", "3-2+", {}}, {"e", "3-2+", {}}, {"^(.*[ij])or$", "3-C+", {}}, {"^(min)or$", "3-C+", {}}, -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like quadripēs, volucripēs). -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- -- Most 3-1 adjectives are i-stem (e.g. audāx) so we require -I -- to be given with non-i-stem adjectives. The first entry below -- will apply when -I isn't given, the second when it is given. {"^(.*ēs)$", "3-1+", {"I"}}, {"^(.*ēs)$", "3-1+", {"par"}}, {"^(.*[ij])ōrēs$", "3-C+", {"pl"}}, {"^(min)ōrēs$", "3-C+", {"pl"}}, -- If .pl with -ēs, we don't know if the adjective is 3-1, 3-2 -- or 3-3. Since 3-2 is probably the most common, we infer it -- (as well as the fact that these adjectives *are* in a sense -- 3-2 since they have a distinct neuter in -(i)a. Note that -- we have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise (and infer a non-i-stem 3-1 adjective). {"ēs", "3-2+", {"pl", "I"}}, {"ēs", "3-1+", {"pl", "par"}, base_as_stem2}, -- Same for neuters. {"ia", "3-2+", {"pl", "I"}}, {"a", "3-1+", {"pl", "par"}, base_as_stem2}, -- As above for -ēs but for miscellaneous singulars. {"", "3-1+", {"I"}}, {"", "3-1+", {"par"}}, } if typ == "+" then local base, new_stem2, rettype, new_subtypes = get_adj_type_and_subtype_by_ending(lemma, stem2, nil, subtypes, decl12_entries, decl12_stem2) if base then return base, new_stem2, rettype, new_subtypes else return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) end elseif typ == "3+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl3_entries, decl3_stem2) elseif typ == "1&2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, decl12_entries, decl12_stem2) elseif typ == "1-1+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"a", typ, {}}, {"ae", typ, {"pl"}}, }) elseif typ == "2-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"us", typ, {}}, {"um", typ, {}}, {"ī", typ, {"pl"}}, {"a", typ, {"pl"}}, {"os", typ, {"greek"}}, {"on", typ, {"greek"}}, {"oe", typ, {"greek", "pl"}}, }) elseif typ == "3-1+" then -- This will cancel out the I if -I is specified in subtypes, and the -- resulting lack of I will get converted to "par". return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { -- Detect -ēs as 3-1 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified. -- Essentially, for declension-3 adjectives, we require that -- .pl is given if the lemma is plural. -- We have two entries here; the first one will apply unless -- -I is given, and will infer an i-stem adjective; the second -- one will apply otherwise. {"^(.*ēs)$", typ, {"I"}}, {"^(.*ēs)$", typ, {"par"}}, {"ēs", typ, {"pl", "I"}, base_as_stem2}, {"ēs", typ, {"pl", "par"}, base_as_stem2}, {"ia", typ, {"pl", "I"}, base_as_stem2}, {"a", typ, {"pl", "par"}, base_as_stem2}, {"", typ, {"I"}}, {"", typ, {"par"}}, }, decl3_stem2) elseif typ == "3-2+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"is", typ, {}}, {"e", typ, {}}, -- Detect -ēs as 3-2 without auto-inferring .pl if .pl -- not specified. If we don't do this, the later entry for -- -ēs will auto-infer .pl whenever -ēs is specified (which -- won't work for adjectives like isoscelēs). Essentially, -- for declension-3 adjectives, we require that .pl is given -- if the lemma is plural. {"ēs", typ, {}}, {"ēs", typ, {"pl"}}, {"ia", typ, {"pl"}}, }, decl3_stem2) elseif typ == "3-3+" or typ == "3-P+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"ēs", typ, {"pl"}, base_as_stem2}, {"ia", typ, {"pl"}, base_as_stem2}, {"", typ, {}}, }, decl3_stem2) elseif typ == "3-C+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(.*[ij])or$", typ, {}}, {"^(min)or$", typ, {}}, {"^(.*[ij])ōrēs$", typ, {"pl"}}, {"^(min)ōrēs$", typ, {"pl"}}, }, decl3_stem2) elseif typ == "irreg+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"^(duo)$", typ, {"pl"}}, {"^(ambō)$", typ, {"pl"}}, {"^(mīll?ia)$", typ, {"N", "pl"}, constant_base("mīlle")}, -- match ea {"^(ea)$", typ, {}, constant_base("is")}, -- match id {"^(id)$", typ, {}, constant_base("is")}, -- match plural eī, iī {"^([ei]ī)$", typ, {"pl"}, constant_base("is")}, -- match plural ea, eae {"^(eae?)$", typ, {"pl"}, constant_base("is")}, -- match eadem {"^(eadem)$", typ, {}, constant_base("īdem")}, -- match īdem, idem {"^([īi]dem)$", typ, {}, constant_base("īdem")}, -- match plural īdem {"^(īdem)$", typ, {"pl"}}, -- match plural eadem, eaedem {"^(eae?dem)$", typ, {"pl"}, constant_base("īdem")}, -- match illa, ipsa, ista; it doesn't matter if we overmatch because -- we'll get an error as we use the stem itself in the returned base {"^(i[lps][lst])a$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match illud, istud; as above, it doesn't matter if we overmatch {"^(i[ls][lt])ud$", typ, {}, function(base, stem2) return base .. "e", nil end}, -- match ipsum {"^(ipsum)$", typ, {}, constant_base("ipse")}, -- match plural illī, ipsī, istī; as above, it doesn't matter if we -- overmatch {"^(i[lps][lst])ī$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- match plural illa, illae, ipsa, ipsae, ista, istae; as above, it -- doesn't matter if we overmatch {"^(i[lps][lst])ae?$", typ, {"pl"}, function(base, stem2) return base .. "e", nil end}, -- Detect quī as non-plural unless .pl specified. {"^(quī)$", typ, {}}, -- Otherwise detect quī as plural. {"^(quī)$", typ, {"pl"}}, -- Same for quae. {"^(quae)$", typ, {}, constant_base("quī")}, {"^(quae)$", typ, {"pl"}, constant_base("quī")}, {"^(quid)$", typ, {}, constant_base("quis")}, {"^(quod)$", typ, {}, constant_base("quī")}, {"^(qui[cd]quid)$", typ, {}, constant_base("quisquis")}, {"^(quīquī)$", typ, {"pl"}, constant_base("quisquis")}, {"^(quaequae)$", typ, {"pl"}, constant_base("quisquis")}, -- match all remaining lemmas in lemma form {"", typ, {}}, }) elseif typ == "indecl+" then return get_adj_type_and_subtype_by_ending(lemma, stem2, typ, subtypes, { {"", typ, {"both"}}, {"", typ, {"sg"}}, {"", typ, {"pl"}}, }) else -- 0+ return lemma, nil, typ, {} end end -- Parse a segment (e.g. "lūna<1>", "aegis/aegid<3.Greek>", "bōs<irreg.F>", -- bonus<+>", or "[[vetus]]/veter<3+.-I>"), consisting of a lemma (or optionally -- a lemma/stem) and declension+subtypes, where a + in the declension indicates -- an adjective. Brackets can be present to indicate links, for use in -- {{la-noun}} and {{la-adj}}. The return value is a table, e.g.: -- { -- decl = "1", -- is_adj = false, -- orig_lemma = "lūna", -- lemma = "lūna", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"lūn"} -- } -- -- or -- -- { -- decl = "3", -- is_adj = false, -- orig_lemma = "aegis", -- lemma = "aegis", -- stem2 = "aegid", -- gender = nil, -- types = {["Greek"] = true}, -- args = {"aegis", "aegid"} -- } -- -- or -- -- { -- decl = "irreg", -- is_adj = false, -- orig_lemma = "bōs", -- lemma = "bōs", -- stem2 = nil, -- gender = "F", -- types = {["F"] = true}, -- args = {"bōs"} -- } -- or -- -- { -- decl = "1&2+", -- is_adj = true, -- orig_lemma = "bonus", -- lemma = "bonus", -- stem2 = nil, -- gender = nil, -- types = {}, -- args = {"bon"} -- } -- -- or -- -- { -- decl = "3-1+", -- is_adj = true, -- orig_lemma = "[[vetus]]", -- lemma = "vetus", -- stem2 = "veter", -- gender = nil, -- types = {}, -- args = {"vetus", "veter"} -- } local function parse_segment(segment) local stem_part, spec_part = segment:match("^(.*)<(.-)>$") local stems = split(stem_part, "/", true, true) local specs = split(spec_part, ".", true, true) local types = {} local num = nil local loc = false local args = {} local decl for j, spec in ipairs(specs) do if j == 1 then decl = spec else local begins_with_hyphen begins_with_hyphen, spec = spec:match("^(%-?)(.*)$") spec = begins_with_hyphen .. spec:gsub("%-", "_") types[spec] = true end end local orig_lemma = stems[1] if not orig_lemma or orig_lemma == "" then orig_lemma = pagename or get_pagename() end local lemma = remove_links(orig_lemma) local stem2 = stems[2] if stem2 == "" then stem2 = nil end if #stems > 2 then error("Too many stems, at most 2 should be given: " .. stem_part) end local base, detected_subtypes local is_adj = false local gender = nil if decl:find("+", nil, true) then base, stem2, decl, detected_subtypes = detect_adj_type_and_subtype(lemma, stem2, decl, types) is_adj = true for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil else types[subtype] = true end end else base, stem2, detected_subtypes = detect_noun_subtype(lemma, stem2, decl, types) for _, subtype in ipairs(detected_subtypes) do if types["-" .. subtype] then -- if a "cancel subtype" spec is given, remove the cancel spec -- and don't apply the subtype types["-" .. subtype] = nil elseif (subtype == "M" or subtype == "F" or subtype == "N") and (types.M or types.F or types.N) then -- if gender already specified, don't create conflicting gender spec elseif (subtype == "sg" or subtype == "pl" or subtype == "both") and (types.sg or types.pl or types.both) then -- if number restriction already specified, don't create conflicting -- number restriction spec else types[subtype] = true end end if not types.pl and not types.both and umatch(lemma, "^%u") then types.sg = true end end if types.loc then loc = true types.loc = nil end if types.M then gender = "M" elseif types.F then gender = "F" elseif types.N then gender = "N" end if types.pl then num = "pl" types.pl = nil elseif types.sg then num = "sg" types.sg = nil end args[1] = base args[2] = stem2 return { decl = decl, is_adj = is_adj, gender = gender, orig_lemma = orig_lemma, lemma = lemma, stem2 = stem2, types = types, num = num, loc = loc, args = args, } end -- Parse a segment run (i.e. a string with zero or more segments [see -- parse_segment] and optional surrounding text, e.g. "foenum<2>-graecum<2>" -- or "[[pars]]/part<3.abl-e-occ-i> [[oratio|ōrātiōnis]]"). The segment run -- currently cannot contain any alternants (e.g. "((epulum<2.sg>,epulae<1>))"). -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments -- has a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of per-word properties, where each element is an -- object { -- decl = DECL (declension), -- types = TYPES (set describing the subtypes of a given word), -- } -- } -- Each element in PARSED_SEGMENTS is as returned by parse_segment() but will -- have an additional .orig_prefix field indicating the text before the segment -- (including bracketed links) and corresponding .prefix field indicating the text -- with bracketed links resolved. If there is trailing text, the last element will -- have only .orig_prefix and .prefix fields containing that trailing text. local function parse_segment_run(segment_run) local loc = nil local num = nil local is_adj = nil -- If the segment run begins with a hyphen, include the hyphen in the -- set of allowed characters for a declined segment. This way, e.g. the -- suffix [[-cen]] can be declared as {{la-ndecl|-cen/-cin<3>}} rather than -- {{la-ndecl|-cen/cin<3>}}, which is less intuitive. local is_suffix = segment_run:sub(1, 1) == "-" local segments = {} local propses = {} -- We want to not break up a bracketed link followed by <> even if it has a space or -- hyphen in it. So we do an outer capturing split to find the bracketed links followed -- by <>, then do inner capturing splits on all the remaining text to find the other -- declined terms. local bracketed_segments = split(segment_run, "(%[%[[^%[%]]-%]%]<.->)") for i, bracketed_segment in ipairs(bracketed_segments) do if i % 2 == 0 then insert(segments, bracketed_segment) else for _, subsegment in ipairs(split(bracketed_segment, is_suffix and "([^<> ,]+<.->)" or "([^<> ,%-]+<.->)")) do insert(segments, subsegment) end end end local parsed_segments = {} local gender = nil for i = 2, (#segments - 1), 2 do local parsed_segment = parse_segment(segments[i]) -- Overall locative is true if any segments call for locative. loc = loc or parsed_segment.loc -- The first specified value for num is used becomes the overall value. num = num or parsed_segment.num if is_adj == nil then is_adj = parsed_segment.is_adj else is_adj = is_adj and parsed_segment.is_adj end gender = gender or parsed_segment.gender parsed_segment.orig_prefix = segments[i - 1] parsed_segment.prefix = remove_links(segments[i - 1]) insert(parsed_segments, parsed_segment) insert(propses, { decl = parsed_segment.decl, types = parsed_segment.types, }) end if segments[#segments] ~= "" then insert(parsed_segments, { orig_prefix = segments[#segments], prefix = remove_links(segments[#segments]), }) end return { segments = parsed_segments, loc = loc, num = num, is_adj = is_adj, gender = gender, propses = propses, } end -- Parse an alternant, e.g. "((epulum<2.sg>,epulae<1>))", -- "((Serapis<3>,Serapis/Serapid<3>))" or -- "((rēs<5>pūblica<1>,rēspūblica<1>))". The return value is a table of the form -- { -- alternants = PARSED_ALTERNANTS (a list of segment runs, each of which is a -- list of parsed segments as returned by parse_segment_run()), -- loc = LOC (a boolean indicating whether any of the individual segment runs -- has a locative), -- num = NUM (the overall number restriction, one of "sg", "pl" or "both"), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all non-constant alternants are adjectives, false -- if all nouns, nil if only constant alternants; conflicting alternants -- cause an error), -- propses = PROPSES (list of lists of per-word property objecs), -- } local function parse_alternant(alternant) local parsed_alternants = {} local alternant_spec = alternant:match("^%(%((.-)%)%)$") local alternants = split(alternant_spec, ",", true, true) local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i, alternant in ipairs(alternants) do local parsed_run = parse_segment_run(alternant) insert(parsed_alternants, parsed_run) loc = loc or parsed_run.loc -- First time through, set the overall num to the num of the first run, -- even if nil. After that, if we ever see a run with a different value -- of num, set the overall num to "both". That way, if all alternants -- don't specify a num, we get an unspecified num, but if some do and -- some don't, we get both, because an unspecified num defaults to -- both. if i == 1 then num = parsed_run.num elseif num ~= parsed_run.num then -- FIXME, this needs to be rethought to allow for -- adjective alternants. num = "both" end gender = gender or parsed_run.gender if is_adj == nil then is_adj = parsed_run.is_adj elseif parsed_run.is_adj ~= nil and parsed_run.is_adj ~= is_adj then error("Saw both noun and adjective alternants; not allowed") end insert(propses, parsed_run.propses) end return { alternants = parsed_alternants, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Parse a segment run (see parse_segment_run()). Unlike for -- parse_segment_run(), this can contain alternants such as -- "((epulum<2.sg>,epulae<1>))" or "((Serapis<3.sg>,Serapis/Serapid<3.sg>))" -- embedded in it to indicate words composed of multiple declensions. -- The return value is a table of the following form: -- { -- segments = PARSED_SEGMENTS (a list of parsed segments), -- loc = LOC (a boolean indicating whether any of the individual segments has -- a locative), -- num = NUM (the first specified value for a number restriction, or nil if -- no number restrictions), -- gender = GENDER (the first specified or inferred gender, or nil if none), -- is_adj = IS_ADJ (true if all segments are adjective segments, false if -- there's at least one noun segment, nil if only raw-text segments), -- propses = PROPSES (list of either per-word property objects or lists of -- lists of such objects), -- }. -- Each element in PARSED_SEGMENTS is one of three types: -- -- 1. A regular segment, as returned by parse_segment() but with additional -- .prefix and .orig_prefix fields indicating the text before the segment, as per -- the return value of parse_segment_run(). -- 2. A raw-text segment, i.e. a table with only .prefix and .orig_prefix fields -- containing the raw text. -- 3. An alternating segment, as returned by parse_alternant(). -- Note that each alternant is a segment run rather than a single parsed -- segment to allow for alternants like "((rēs<5>pūblica<1>,rēspūblica<1>))". -- The parsed segment runs in PARSED_SEGMENT_RUNS are tables as returned by -- parse_segment_run() (of the same form as the overall return value of -- parse_segment_run_allowing_alternants()). local function parse_segment_run_allowing_alternants(segment_run) if segment_run:find(" ", nil, true) then track("has-space") end if segment_run:find("((", nil, true) then track("has-alternant") end local alternating_segments = split(segment_run, "(%(%(.-%)%))") local parsed_segments = {} local loc = false local num = nil local gender = nil local is_adj = nil local propses = {} for i = 1, #alternating_segments do local alternating_segment = alternating_segments[i] if alternating_segment ~= "" then local this_is_adj if i % 2 == 1 then local parsed_run = parse_segment_run(alternating_segment) for _, parsed_segment in ipairs(parsed_run.segments) do insert(parsed_segments, parsed_segment) end loc = loc or parsed_run.loc num = num or parsed_run.num gender = gender or parsed_run.gender this_is_adj = parsed_run.is_adj for _, props in ipairs(parsed_run.propses) do insert(propses, props) end else local parsed_alternating_segment = parse_alternant(alternating_segment) insert(parsed_segments, parsed_alternating_segment) loc = loc or parsed_alternating_segment.loc num = num or parsed_alternating_segment.num gender = gender or parsed_alternating_segment.gender this_is_adj = parsed_alternating_segment.is_adj insert(propses, parsed_alternating_segment.propses) end if is_adj == nil then is_adj = this_is_adj elseif this_is_adj ~= nil then is_adj = is_adj and this_is_adj end end end if #parsed_segments > 1 then track("multiple-segments") end return { segments = parsed_segments, loc = loc, num = num, gender = gender, is_adj = is_adj, propses = propses, } end -- Combine each form in FORMS (a list of forms associated with a slot) with each -- form in NEW_FORMS (either a single string for a single form, or a list of -- forms) by concatenating EXISTING_FORM .. PREFIX .. NEW_FORM. Also combine -- NOTES (a table specifying the footnotes associated with each existing form, -- i.e. a map from form indices to lists of footnotes) with NEW_NOTES (new -- footnotes associated with the new forms, in the same format as NOTES). Return -- a pair NEW_FORMS, NEW_NOTES where either or both of FORMS and NOTES (but not -- the sublists in NOTES) may be destructively modified to generate the return -- values. local function append_form(forms, notes, new_forms, new_notes, prefix) if forms == nil then return end new_forms = new_forms or "" notes = notes or {} new_notes = new_notes or {} prefix = prefix or "" if type(new_forms) == "table" and #new_forms == 1 then new_forms = new_forms[1] end if type(new_forms) == "string" then -- If there's only one new form, destructively modify the existing -- forms and notes for this new form and its footnotes. for i = 1, #forms do forms[i] = forms[i] .. prefix .. new_forms if new_notes[1] then if not notes[i] then notes[i] = new_notes[1] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[1]) do insert(combined_notes, note) end notes[i] = combined_notes end end end return forms, notes else -- If there are multiple new forms, we need to loop over all -- combinations of new and old forms. In that case, use new tables -- for the combined forms and notes. local ret_forms = {} local ret_notes = {} for i=1, #forms do for j=1, #new_forms do insert(ret_forms, forms[i] .. prefix .. new_forms[j]) if new_notes[j] then if not notes[i] then -- We are constructing a linearized matrix of size -- NI x NJ where J is in the inner loop. If I and J -- are zero-based, the linear index of (I, J) is -- I * NJ + J. However, we are one-based, so the -- same formula won't work. Instead, we effectively -- need to convert to zero-based indices, compute -- the zero-based linear index, and then convert it -- back to a one-based index, i.e. -- -- (I - 1) * NJ + (J - 1) + 1 -- -- i.e. (I - 1) * NJ + J. ret_notes[(i - 1) * #new_forms + j] = new_notes[j] else local combined_notes = deep_copy(notes[i]) for _, note in ipairs(new_notes[j]) do insert(combined_notes, note) end ret_notes[(i - 1) * #new_forms + j] = combined_notes end end end end return ret_forms, ret_notes end end -- Destructively modify any forms in FORMS (a map from a slot to a form or a -- list of forms) by converting sequences of ae, oe, Ae or Oe to the -- appropriate ligatures. local function apply_ligatures(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then forms[slot] = forms[slot]:gsub("[AaOo]e", ligatures) elseif type(forms[slot]) == "table" then for i = 1, #forms[slot] do forms[slot][i] = forms[slot][i]:gsub("[AaOo]e", ligatures) end end end end -- Modify any forms in FORMS (a map from a slot to a form or a list of forms) by -- converting final m to optional n or m. local function apply_sufn(forms, is_adj) for slot in iter_slots(is_adj) do if type(forms[slot]) == "string" then if forms[slot]:sub(-1) == "m" then forms[slot] = {forms[slot]:gsub("m$", "n"), forms[slot]} end elseif type(forms[slot]) == "table" then -- See if there are any final m's. local final_m for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then final_m = true break end end if final_m then local newval = {} for i = 1, #forms[slot] do if forms[slot][i]:sub(-1) == "m" then insert(newval, (forms[slot][i]:gsub("m$", "n"))) end insert(newval, forms[slot][i]) end forms[slot] = newval end end end end -- If NUM == "sg", copy the singular forms to the plural ones; vice-versa if -- NUM == "pl". This should allow for the equivalent of plural -- "alpha and omega" formed from two singular nouns, and for the equivalent of -- plural "St. Vincent and the Grenadines" formed from a singular noun and a -- plural noun. (These two examples actually occur in Russian, at least.) local function propagate_number_restrictions(forms, num, is_adj) if num == "sg" or num == "pl" then for slot in iter_slots(is_adj) do if slot:find(num, nil, true) then local other_num_slot = num == "sg" and slot:gsub("sg", "pl") or slot:gsub("pl", "sg") forms[other_num_slot] = type(forms[slot]) == "table" and deep_copy(forms[slot]) or forms[slot] end end end end local function join_sentences(sentences, joiner) -- Lowercase the first letter of all but the first sentence, and remove the -- final period from all but the last sentence. Then join together with the -- joiner (e.g. " and " or " or "). -- FIXME: Should we join three or more as e.g. "foo, bar and baz"? local sentences_to_join = {} for i, sentence in ipairs(sentences) do if i < #sentences then sentence = sentence:gsub("%.$", "") end if i > 1 then sentence = lcfirst(sentence) end insert(sentences_to_join, sentence) end return concat(sentences_to_join, joiner) end -- Construct the declension of a parsed segment run of the form returned by -- parse_segment_run() or parse_segment_run_allowing_alternants(). Return value -- is a table -- { -- forms = FORMS (keyed by slot, list of forms for that slot), -- notes = NOTES (keyed by slot, map from form indices to lists of footnotes), -- title = TITLE (list of titles for each segment in the run), -- categories = CATEGORIES (combined categories for all segments), -- } local function decline_segment_run(parsed_run, pos, is_adj) local declensions = { -- For each possible slot (e.g. "abl_sg"), list of possible forms. forms = {}, -- Keyed by slot (e.g. "abl_sg"). Value is a table indicating the footnotes -- corresponding to the forms for that slot. Each such table maps indices -- (the index of the corresponding form) to a list of one or more -- footnotes. notes = {}, title = {}, unattested = {}, subtitleses = {}, orig_titles = {}, categories = {}, footnotes = {}, -- May be set true if declining a 1-1 adjective loc = false, noneut = false, nomf = false, } for slot in iter_slots(is_adj) do declensions.forms[slot] = {""} end for i, seg in ipairs(parsed_run.segments) do local decl = seg.decl if decl then -- not an alternant, not a constant segment seg.loc = parsed_run.loc seg.num = seg.num or parsed_run.num seg.gender = seg.gender or parsed_run.gender local data, potential_lemma_slots if seg.is_adj then if not (m_adj_decl or get_m_adj_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_adj_lemma_slots data = { subtitles = {}, num = seg.num or "", gender = seg.gender, loc = seg.loc, noneut = false, nomf = false, pos = is_adj and pos or "နာမဝိသေသန", forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_adj_decl or get_m_adj_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl if data.loc then declensions.loc = true end if data.noneut then declensions.noneut = true end if data.nomf then declensions.nomf = true end -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg+" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl+" or apparent_decl == "0+" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize adjective declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with ''idem'', ''quīdam'' insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) else if not (m_noun_decl or get_m_noun_decl())[decl] then error("Unrecognized declension '" .. decl .. "'") end potential_lemma_slots = potential_noun_lemma_slots data = { subtitles = {}, num = seg.num or "", loc = seg.loc, pos = pos, forms = {}, types = seg.types, unattested = {}, categories = {}, notes = {}, } (m_noun_decl or get_m_noun_decl())[decl](data, seg.args) local apparent_decl = data.decl or decl parsed_run.propses[i].headword_decl = apparent_decl -- Construct title out of "original title" and subtitles. if not data.title then if decl == "irreg" and apparent_decl ~= decl and #data.subtitles == 0 then insert(data.subtitles, glossary_link("ပါ်ပါဲထောံဟွံမာန်")) end if declension_to_english[apparent_decl] then local english = declension_to_english[apparent_decl] data.title = "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်" .. english .. "|မလဟုတ်စှ်ေအလန်" .. english .. "]]" elseif apparent_decl == "irreg" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") elseif apparent_decl == "indecl" or apparent_decl == "0" or apparent_decl == "sgpl" then data.title = glossary_link("ပါ်ပါဲထောံဟွံမာန်") else error("Internal error! Don't recognize noun declension " .. apparent_decl) end data.title = data.title .. data.pos end if data.types.sufn then insert(data.subtitles, {"with", " ''m'' optionally → ''n'' in compounds"}) elseif data.types.not_sufn then insert(data.subtitles, {"without", " ''m'' optionally → ''n'' in compounds"}) end -- Record original title and subtitles for use in alternant title-constructing code. insert(declensions.orig_titles, data.title) if #data.subtitles > 0 then local subtitles = {} for _, subtitle in ipairs(data.subtitles) do if type(subtitle) == "table" then -- Occurs e.g. with 1st-declension ''-ābus'' ending where -- we want a common prefix to be extracted out if possible -- in the alternant title-generating code. insert(subtitles, concat(subtitle)) else insert(subtitles, subtitle) end end data.title = data.title .. " (" .. concat(subtitles, ",") .. ")" end insert(declensions.subtitleses, data.subtitles) end -- Generate linked variants of slots that may be the lemma. -- If the form is the same as the lemma (with links removed), -- substitute the original lemma (with links included). for _, slot in ipairs(potential_lemma_slots) do local forms = data.forms[slot] if forms then local linked_forms = {} if type(forms) ~= "table" then forms = {forms} end for _, form in ipairs(forms) do if form == seg.lemma then insert(linked_forms, seg.orig_lemma) else insert(linked_forms, form) end end data.forms["linked_" .. slot] = linked_forms end end if seg.types.lig then apply_ligatures(data.forms, is_adj) end if seg.types.sufn then apply_sufn(data.forms, is_adj) end propagate_number_restrictions(data.forms, seg.num, is_adj) for slot in iter_slots(is_adj) do -- 1. Select the forms to append to the existing ones. local new_forms if is_adj then if not seg.is_adj then error("Can't decline noun '" .. seg.lemma .. "' when overall term is an adjective") end new_forms = data.forms[slot] if not new_forms and slot:find("_[fn]$") then new_forms = data.forms[slot:gsub("_[fn]$", "_m")] end elseif seg.is_adj then if not seg.gender then error("Declining modifying adjective " .. seg.lemma .. " but don't know gender of associated noun") end -- Select the appropriately gendered equivalent of the case/number -- combination. Some adjectives won't have feminine or neuter -- variants, though (e.g. 3-1 and 3-2 adjectives don't have a -- distinct feminine), so in that case select the masculine. new_forms = data.forms[slot .. "_" .. mw.ustring.lower(seg.gender)] or data.forms[slot .. "_m"] else new_forms = data.forms[slot] end -- 2. Extract the new footnotes in the format we require, which is -- different from the format passed in by the declension functions. local new_notes = {} if type(new_forms) == "string" and data.notes[slot .. "1"] then new_notes[1] = {data.notes[slot .. "1"]} elseif new_forms then for j = 1, #new_forms do if data.notes[slot .. j] then new_notes[j] = {data.notes[slot .. j]} end end end -- 3. Append new forms and footnotes to the existing ones. new_forms = normalize_form(new_forms) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, new_notes, slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end end for slot, v in pairs(data.unattested) do if v then declensions.unattested[slot] = true end end if not seg.types.nocat and (is_adj or not seg.is_adj) then for _, cat in ipairs(data.categories) do insert_if_not(declensions.categories, cat) end end if data.footnote then insert(declensions.footnotes, data.footnote) end if seg.prefix ~= "" and seg.prefix ~= "-" and seg.prefix ~= " " then insert(declensions.title, glossary_link("indeclinable") .. "portion") end insert(declensions.title, data.title) elseif seg.alternants then local seg_declensions = nil local seg_titles = {} local seg_subtitleses = {} local seg_stems_seen = {} local seg_unattested = {} local seg_categories = {} local seg_footnotes = {} -- If all alternants have exactly one non-constant segment and all are -- of the same declension, we use special code that displays the -- differences in the subtitles. Otherwise we use more general code -- that displays the full title and subtitles of each segment, -- separating segment combined titles by "and" and the segment-run -- combined titles by "or". local title_the_hard_way = false local alternant_decl = nil local alternant_decl_title = nil for _, this_parsed_run in ipairs(seg.alternants) do local num_non_constant_segments = 0 for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then if not alternant_decl then alternant_decl = segment.decl elseif alternant_decl ~= segment.decl then title_the_hard_way = true num_non_constant_segments = 500 break end num_non_constant_segments = num_non_constant_segments + 1 end end if num_non_constant_segments ~= 1 then title_the_hard_way = true break end end if not title_the_hard_way then -- If using the special-purpose code, find the subtypes that are -- not present in a given alternant but are present in at least -- one other, and record "negative" variants of these subtypes -- so that the declension-construction code can record subtitles -- for these negative variants (so we can construct text like -- "i-stem or imparisyllabic non-i-stem"). local subtypeses = {} for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then insert(subtypeses, segment.types) insert_if_not(seg_stems_seen, segment.stem2) end end end local union = set_union(subtypeses) for _, this_parsed_run in ipairs(seg.alternants) do for _, segment in ipairs(this_parsed_run.segments) do if segment.decl then local neg_subtypes = set_difference(union, segment.types) for neg_subtype, _ in pairs(neg_subtypes) do segment.types["not_" .. neg_subtype] = true end end end end end for _, this_parsed_run in ipairs(seg.alternants) do this_parsed_run.loc = seg.loc this_parsed_run.num = this_parsed_run.num or seg.num this_parsed_run.gender = this_parsed_run.gender or seg.gender local this_declensions = decline_segment_run(this_parsed_run, pos, is_adj) if this_declensions.noneut then declensions.noneut = true end if this_declensions.nomf then declensions.nomf = true end -- If there's a number restriction on the segment run, blank -- out the forms outside the restriction. This allows us to -- e.g. construct heteroclites that decline one way in the -- singular and a different way in the plural. if this_parsed_run.num == "sg" or this_parsed_run.num == "pl" then for slot in iter_slots(is_adj) do if this_parsed_run.num == "sg" and slot:find("pl", nil, true) or this_parsed_run.num == "pl" and slot:find("sg", nil, true) then this_declensions.forms[slot] = {} this_declensions.notes[slot] = nil end end end if not seg_declensions then seg_declensions = this_declensions else for slot in iter_slots(is_adj) do -- For a given slot, combine the existing and new forms. -- We do this by checking to see whether a new form is -- already present and not adding it if so; in the -- process, we keep a map from indices in the new forms -- to indices in the combined forms, for use in -- combining footnotes below. local curforms = seg_declensions.forms[slot] or {} local newforms = this_declensions.forms[slot] or {} local newform_index_to_new_index = {} for newj, form in ipairs(newforms) do local did_break = false for j = 1, #curforms do if curforms[j] == form then newform_index_to_new_index[newj] = j did_break = true break end end if not did_break then insert(curforms, form) newform_index_to_new_index[newj] = #curforms end end seg_declensions.forms[slot] = curforms -- Now combine the footnotes. Keep in mind that -- each form may have its own set of footnotes, and -- in some cases we didn't add a form from the new -- list of forms because it already occurred in the -- existing list of forms; in that case, we combine -- footnotes from the two sources. local curnotes = seg_declensions.notes[slot] local newnotes = this_declensions.notes[slot] if newnotes then if not curnotes then curnotes = {} end for index, notes in pairs(newnotes) do local combined_index = newform_index_to_new_index[index] if not curnotes[combined_index] then curnotes[combined_index] = notes else local combined = mw.clone(curnotes[combined_index]) for _, note in ipairs(newnotes) do insert_if_not(combined, note) end curnotes[combined_index] = combined end end end end end for slot, v in pairs(this_declensions.unattested) do if v then seg_unattested[slot] = true end end for _, cat in ipairs(this_declensions.categories) do insert_if_not(seg_categories, cat) end for _, footnote in ipairs(this_declensions.footnotes) do insert_if_not(seg_footnotes, footnote) end insert_if_not(seg_titles, this_declensions.title) for _, subtitles in ipairs(this_declensions.subtitleses) do insert(seg_subtitleses, subtitles) end if not alternant_decl_title then alternant_decl_title = this_declensions.orig_titles[1] end end -- If overall run is singular, copy singular to plural, and -- vice-versa. See propagate_number_restrictions() for rationale; -- also, this should eliminate cases of empty forms, which will -- cause the overall set of forms for that slot to be empty. propagate_number_restrictions(seg_declensions.forms, parsed_run.num, is_adj) for slot in iter_slots(is_adj) do local new_forms = normalize_form(seg_declensions.forms[slot]) if new_forms == nil then declensions.forms[slot] = nil declensions.notes[slot] = nil else declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], new_forms, seg_declensions.notes[slot], nil) end end for slot, v in pairs(seg_unattested) do if v then declensions.unattested[slot] = true end end if is_adj or not seg.is_adj then for _, cat in ipairs(seg_categories) do insert_if_not(declensions.categories, cat) end end for _, footnote in ipairs(seg_footnotes) do insert_if_not(declensions.footnotes, footnote) end local title_to_insert if title_the_hard_way then title_to_insert = join_sentences(seg_titles, " or ") else -- Special-purpose title-generation code, for the common -- situation where each alternant has single-segment runs and -- all segments belong to the same declension. -- -- 1. Find the initial subtitles common to all segments. local first_subtitles = seg_subtitleses[1] local num_common_subtitles = #first_subtitles for j = 2, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] for k = 1, num_common_subtitles do if not deep_equals(first_subtitles[k], this_subtitles[k]) then num_common_subtitles = k - 1 break end end end -- 2. Construct the portion of the text based on the common subtitles. local common_subtitles = {} for j = 1, num_common_subtitles do if type(first_subtitles[j]) == "table" then insert(common_subtitles, concat(first_subtitles[j])) else insert(common_subtitles, first_subtitles[j]) end end local common_subtitle_portion = concat(common_subtitles, ", ") local non_common_subtitle_portion -- 3. Special-case the situation where there's one non-common -- subtitle in each segment and a common prefix or suffix to -- all of them. local common_prefix, common_suffix for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] if #this_subtitles ~= num_common_subtitles + 1 or type(this_subtitles[num_common_subtitles + 1]) ~= "table" or #this_subtitles[num_common_subtitles + 1] ~= 2 then break end if j == 1 then common_prefix = this_subtitles[num_common_subtitles + 1][1] common_suffix = this_subtitles[num_common_subtitles + 1][2] else local this_prefix = this_subtitles[num_common_subtitles + 1][1] local this_suffix = this_subtitles[num_common_subtitles + 1][2] if this_prefix ~= common_prefix then common_prefix = nil end if this_suffix ~= common_suffix then common_suffix = nil end if not common_prefix and not common_suffix then break end end end if common_prefix or common_suffix then if common_prefix and common_suffix then error("Something is wrong, first non-common subtitle is actually common to all segments") end if common_prefix then local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][2]) end non_common_subtitle_portion = common_prefix .. concat(non_common_parts, " or ") else local non_common_parts = {} for j = 1, #seg_subtitleses do insert(non_common_parts, seg_subtitleses[j][num_common_subtitles + 1][1]) end non_common_subtitle_portion = concat(non_common_parts, " or ") .. common_suffix end else -- 4. Join the subtitles that differ from segment to segment. -- Record whether there are any such differing subtitles. -- If some segments have differing subtitles and others don't, -- we use the text "otherwise" for the segments without -- differing subtitles. local saw_non_common_subtitles = false local non_common_subtitles = {} for j = 1, #seg_subtitleses do local this_subtitles = seg_subtitleses[j] local this_non_common_subtitles = {} for k = num_common_subtitles + 1, #this_subtitles do if type(this_subtitles[k]) == "table" then insert(this_non_common_subtitles, concat(this_subtitles[k])) else insert(this_non_common_subtitles, this_subtitles[k]) end end if #this_non_common_subtitles > 0 then insert(non_common_subtitles, concat(this_non_common_subtitles, ", ")) saw_non_common_subtitles = true else insert(non_common_subtitles, "otherwise") end end non_common_subtitle_portion = saw_non_common_subtitles and concat(non_common_subtitles, " or ") or "" end -- 5. Combine the common and non-common subtitle portions. local subtitle_portions = {} if common_subtitle_portion ~= "" then insert(subtitle_portions, common_subtitle_portion) end if non_common_subtitle_portion ~= "" then insert(subtitle_portions, non_common_subtitle_portion) end if #seg_stems_seen > 1 then insert(subtitle_portions, (number_to_english[#seg_stems_seen] or "" .. #seg_stems_seen) .. "different stems" ) end local subtitle_portion = concat(subtitle_portions, ";") if subtitle_portion ~= "" then title_to_insert = alternant_decl_title .. " (" .. subtitle_portion .. ")" else title_to_insert = alternant_decl_title end end -- Don't insert blank title (happens e.g. with "((ali))quis<irreg+>"). if title_to_insert ~= "" then insert(declensions.title, title_to_insert) end else for slot in iter_slots(is_adj) do declensions.forms[slot], declensions.notes[slot] = append_form( declensions.forms[slot], declensions.notes[slot], slot:find("linked", nil, true) and seg.orig_prefix or seg.prefix) end insert(declensions.title, glossary_link("ပါ်ပါဲထောံဟွံမာန်") .. "အၚ်္ဂ") end end -- First title is uppercase, remainder have an indefinite article, joined -- using "with". local titles = {} for i, title in ipairs(declensions.title) do if i == 1 then insert(titles, ucfirst(title)) else insert(titles, add_indefinite_article(title)) end end declensions.title = concat(titles, " with ") return declensions end local function construct_title(args_title, declensions_title, generate_type, parsed_run) if args_title then declensions_title = args_title:gsub("<1>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|မလဟုတ်စှ်ေအလန်ပဌမ]]") declensions_title = declensions_title:gsub("<1&2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဌမ|ပဌမ]]/[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<2>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ဒုတိယ|မလဟုတ်စှ်ေအလန်ဒုတိယ]]") declensions_title = declensions_title:gsub("<3>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်တတိယ|မလဟုတ်စှ်ေအလန်တတိယ]]") declensions_title = declensions_title:gsub("<4>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်စတုတ္ထ|မလဟုတ်စှ်ေအလန်စတုတ္ထ]]") declensions_title = declensions_title:gsub("<5>", "[[Appendix:လပ်တေန်မလဟုတ်စှ်ေအလန်ပဉ္စမ|မလဟုတ်စှ်ေအလန်ပဉ္စမ]]") if generate_type == "headword" then declensions_title = lcfirst((declensions_title:gsub("%.$", ""))) else declensions_title = ucfirst(declensions_title) end else local post_text_parts = {} if parsed_run.loc then insert(post_text_parts, ",မနွံကဵုခၞံဗဒှ်လဝ်") end if parsed_run.num == "sg" then insert(post_text_parts, ",ပါဲနူကိုန်ဨကဝုစ်") elseif parsed_run.num == "pl" then insert(post_text_parts, ",ပါဲနူကိုန်ဗဟုဝစ်") end local post_text = concat(post_text_parts) if generate_type == "headword" then declensions_title = post_text .. lcfirst(declensions_title) else declensions_title = post_text .. ucfirst(declensions_title) .. "။" end end return declensions_title end function export.do_generate_noun_forms(parent_args, pos, generate_type, def) local params = { [1] = {required = true, default = def or "aqua<1>"}, footnote = true, title = true, num = true, json = {type = "boolean"}, } for slot in iter_noun_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.id = true params.cat = list params.m = sublist params.f = sublist params.g = list params.indecl = {type = "boolean"} end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local parsed_run = parse_segment_run_allowing_alternants(args[1]) parsed_run.loc = parsed_run.loc or not not (args.loc_sg or args.loc_pl) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, false) if not parsed_run.loc then declensions.forms.loc_sg = nil declensions.forms.loc_pl = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", gender = parsed_run.gender, propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, overriding_lemma = args.lemma, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, m = args.m, f = args.f, overriding_genders = args.g, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_noun_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_noun_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.do_generate_adj_forms(parent_args, pos, generate_type, degree, def) local boolean = {type = "boolean"} local params = { [1] = {required = true, default = def or "bonus"}, footnote = true, title = true, num = true, noneut = boolean, nomf = boolean, json = boolean, } for slot in iter_adj_slots() do params[slot] = true end if generate_type == "headword" then local list = {list = true} local sublist = {sublist = "/"} params.lemma = list params.adv = sublist params.id = true params.cat = list params.indecl = boolean if degree == "ပတုပ်ရံၚ်" or degree == "သဒ္ဒာ" then params.positive = sublist end if degree ~= "ပတုပ်ရံၚ်" then params.comp = sublist end if degree ~= "သဒ္ဒာ" then params.sup = sublist end end if pos == "numerals" then params["type"] = true end local args = process_params(parent_args, params) if args.title then track("overriding-title") end local segment_run = args[1] if not segment_run:match("[<(]") then -- If the segment run doesn't have any explicit declension specs or alternants, -- add a default declension spec of <+> to it (or <0+> for indeclinable -- adjectives). This allows the majority of adjectives to just specify -- the lemma. segment_run = segment_run .. (args.indecl and "<0+>" or "<+>") end local parsed_run = parse_segment_run_allowing_alternants(segment_run) parsed_run.loc = parsed_run.loc or not not ( args.loc_sg_m or args.loc_sg_f or args.loc_sg_n or args.loc_pl_m or args.loc_pl_f or args.loc_pl_n ) parsed_run.num = args.num or parsed_run.num local declensions = decline_segment_run(parsed_run, pos, true) if not parsed_run.loc then declensions.forms.loc_sg_m = nil declensions.forms.loc_sg_f = nil declensions.forms.loc_sg_n = nil declensions.forms.loc_pl_m = nil declensions.forms.loc_pl_f = nil declensions.forms.loc_pl_n = nil end declensions.title = construct_title(args.title, declensions.title, generate_type, parsed_run) local all_data = { title = declensions.title, footnotes = {}, num = parsed_run.num or "", propses = parsed_run.propses, forms = declensions.forms, unattested = declensions.unattested, categories = declensions.categories, notes = {}, user_specified = {}, accel = {}, loc = declensions.loc, noneut = args.noneut or declensions.noneut, nomf = args.nomf or declensions.nomf, overriding_lemma = args.lemma, positive = args.positive, comp = args.comp, sup = args.sup, adv = args.adv, id = args.id, pos = pos, cat = args.cat, indecl = args.indecl, num_type = args["type"], } if generate_type ~= "bare" then all_data.accel = {} end if args.footnote then insert_if_not(all_data.footnotes, args.footnote) end for _, footnote in ipairs(declensions.footnotes) do insert_if_not(all_data.footnotes, footnote) end for slot in iter_adj_slots() do if declensions.notes[slot] then for index, notes in pairs(declensions.notes[slot]) do all_data.notes[slot .. index] = notes end end end process_adj_forms_and_overrides(all_data, args, generate_type) if args.json then return require(json_module).toJSON(all_data) end return all_data end function export.show_noun(frame) local parent_args = frame:getParent().args local data = export.do_generate_noun_forms(parent_args, "နာမ်") if type(data) == "string" then -- JSON return data end show_forms(data, false) local num = data.num if num == "sg" then return make_noun_table_sg(data) elseif num == "pl" then return make_noun_table_pl(data) end return make_noun_table(data) end function export.show_adj(frame) local parent_args = frame:getParent().args local data = export.do_generate_adj_forms(parent_args, "နာမဝိသေသန") if type(data) == "string" then -- JSON return data end partial_show_forms(data, true) return make_adj_table(data) end return export gbe5zpacegmoevb3slukuv5tu5z1tcy မဝ်ဂျူ:la-utilities 828 6721 396229 300949 2026-06-03T15:03:14Z 咽頭べさ 33 396229 Scribunto text/plain local export = {} local debug_track_module = "Module:debug/track" local string_utilities_module = "Module:string utilities" local table_module = "Module:table" local gsub = string.gsub local ipairs = ipairs local join -- defined below local match = string.match local normalize_form -- defined below local pairs = pairs local remove = table.remove local require = require local toNFC = mw.ustring.toNFC local toNFD = mw.ustring.toNFD local type = type local u = mw.ustring.char local umatch = mw.ustring.match local MACRON = u(0x304) local VOWEL = "[aæeioœuyAÆEIOŒUY]" local function contains(...) contains = require(table_module).contains return contains(...) end local function debug_track(...) debug_track = require(debug_track_module) return debug_track(...) end local function decode_entities(...) decode_entities = require(string_utilities_module).decode_entities return decode_entities(...) end local function deep_equals(...) deep_equals = require(table_module).deepEquals return deep_equals(...) end local function insert_if_not(...) insert_if_not = require(table_module).insertIfNot return insert_if_not(...) end local function table_len(...) table_len = require(table_module).length return table_len(...) end local function trim(...) trim = require(string_utilities_module).trim return trim(...) end local function ugsub(...) ugsub = require(string_utilities_module).gsub return ugsub(...) end export.cases = { ["nom"] = "မဒုၚ်ယၟု", ["gen"] = "ဗဳဇဂကူ", ["dat"] = "ပြကမ္မကာရက", ["acc"] = "ကမ္မကာရက", ["abl"] = "ပရေၚ်စောဲလာံ", ["voc"] = "ပရေၚ်ဂယိုၚ်လမျီု", ["loc"] = "ခၞံဗဒှ်ဌာန်မတန်တဴ", } local cons_to_vowel = { ["j"] = "i", ["J"] = "I", ["v"] = "u", ["V"] = "U", } local function link_if_unlinked(text) return match(text, "%[%[.-]]") and text or ugsub(text, "^(%s*)(.-)(%s*)$", "%1[[%2]]%3") end function export.join(a, b) a, b = toNFD(a), toNFD(b) -- If the first part ends in "j" or "v", convert it to "i" or "u" unless -- the second part begins with a vowel. if not umatch(b, "^" .. VOWEL) then a = gsub(a, "[jvJV]$", cons_to_vowel) end -- If there is a space between the two forms, link both parts separately. if umatch(a, "%s$") or umatch(b, "^%s") then a, b = link_if_unlinked(a), link_if_unlinked(b) end return toNFC(a .. b) end join = export.join local function normalized_form_is_empty(form) local cancelled_forms = require(table_module).listToSet{"", "-", "–", "—", "―", "⸺", "⸻"} function normalized_form_is_empty(form) return not (form and not cancelled_forms[form]) end return normalized_form_is_empty(form) end function export.normalize_form(form) if form == nil then return nil elseif normalized_form_is_empty(form) then return "-" end local form_type = type(form) if form_type ~= "table" then if form_type == "string" then form = trim(decode_entities(form)) end return normalized_form_is_empty(form) and "-" or form end local i, subform = 1, form[1] while subform ~= nil do subform = normalize_form(subform) if normalized_form_is_empty(subform) then remove(form, i) else -- Check against all earlier subforms, in case it's a duplicate. -- Use a loop rather than a table lookup, as it's more efficient -- when the number of subforms is less than 5, which is almost -- always the case. local duplicate = false for j = 1, i - 1 do if deep_equals(subform, form[j]) then duplicate = true remove(form, i) break end end if not duplicate then form[i] = subform i = i + 1 end end subform = form[i] end local form_len = i - 1 if form_len == 0 then return "-" elseif form_len == 1 then return form[1] end return form end normalize_form = export.normalize_form function export.form_is_empty(form) return normalized_form_is_empty(normalize_form(form)) end -- For a given form, we allow either strings (a single form) or lists of forms, -- and treat strings equivalent to one-element lists. function export.forms_equal(form1, form2) return deep_equals(normalize_form(form1), normalize_form(form2)) end function export.form_contains(form, str) form = normalize_form(form) if normalized_form_is_empty(form) then return false end str = normalize_form(str) if type(form) ~= "table" then return deep_equals(form, str) end return contains(form, str) end -- Add a value to a given form key, e.g. "1s_pres_actv_indc". If the value is -- already present in the key, it won't be added again. -- -- The value is formed by concatenating `stem` and `suf`. `suf` can be a list, -- in which case `stem` will be concatenated in turn to each value in the list -- and all the resulting forms added to the key. -- -- `pos` is the position to insert the form(s) at; default is at the end. To -- insert at the beginning, specify 1 for `pos`. do local options = {} local function _add_form(forms, slot, stem, suf, pos) local curr_form = normalize_form(forms[slot]) local new_form = normalize_form(suf == nil and stem or join(stem, suf)) if normalized_form_is_empty(curr_form) then forms[slot] = new_form return elseif deep_equals(curr_form, new_form) then forms[slot] = curr_form return pos elseif type(curr_form) ~= "table" then curr_form = {curr_form} end options.pos = pos local success = insert_if_not(curr_form, new_form, options) forms[slot] = curr_form return pos ~= nil and success and pos + 1 or pos end local function add_stem(forms, slot, stem, suf, pos) if suf and type(suf) == "table" then for _, s in ipairs(suf) do pos = _add_form(forms, slot, stem, s, pos) end return pos else return _add_form(forms, slot, stem, suf, pos) end end local function add_slot(forms, slot, stem, suf, pos) -- Bound `pos` between 1 and the current number of forms + 1. if pos then local form = forms[slot] if not form then pos = nil elseif pos <= 1 then pos = 1 elseif not (type(form) == "table" and pos <= table_len(form)) then pos = nil end end if type(stem) == "table" then for _, s in ipairs(stem) do pos = add_stem(forms, slot, s, suf, pos) end else add_stem(forms, slot, stem, suf, pos) end end --[==[ Adds one or more forms to `forms`, which is a table of inflections: * `slot` is the specifier for the form (e.g. "gen_sg"). This does not need to exist before this function is called. * `stem` is the stem for the form. If `suf` is supplied, `stem` and `suf` will be combined using `exprt.join()` (which accounts for i/j and u/v alternation), and added to the relevant slot(s). If `suf` is not supplied, `stem` will be taken as the form. * Any or all of `slot`, `stem` and `suf` can optionally be given as a list, in which case all stem/suffix combinations will be generated, which will be added to each of the listed slots. This is useful when adding multiple forms to the same slot, or when the forms are identical between slots (or both). * If `pos` is supplied, the form(s) will be added to at the specified position in each slot specified. Note that this function automatically handles duplicates, forms as strings, forms as lists, and cancelled forms (specified with "-").]==] function export.add_form(forms, slot, stem, suf, pos) if type(slot) == "table" then for _, s in ipairs(slot) do pos = add_slot(forms, s, stem, suf, pos) end else add_slot(forms, slot, stem, suf, pos) end end end do local check_keytypes local function check_exceptions(slot, forms, keytypes, exceptions) for _, keytype in ipairs(exceptions) do if match(slot, keytype) then return true end end if keytypes then check_keytypes(slot, forms, keytypes) end end function check_keytypes(slot, forms, keytypes, exceptions) for _, keytype in ipairs(keytypes) do if match(slot, keytype) and not (exceptions and check_exceptions(slot, forms, nil, exceptions)) then forms[slot] = nil return end end end -- Remove all forms with a key matching any of the keys in the list -- `keytypes`, unless they match any keytypes listed in `exceptions`. function export.remove_forms(forms, keytypes, exceptions) -- Check the shorter list first. local func = (exceptions == nil or #exceptions >= #keytypes) and check_keytypes or check_exceptions for slot in pairs(forms) do func(slot, forms, keytypes, exceptions) end end end local patterns = { {"[mM]a", "%0t"}, {"e", ""}, {"([aoAO])([lr])", "%1" .. MACRON .. "%2"}, {"[eE]l", "%0l"}, {"([mM])en", "%1in"}, {"([tT]ūd)ō", "%1in"}, {"([gG])ō", "%1in"}, {"[ōŌ]", "%1n"}, {"er", "r"}, {"[ēi]s", ""}, {"([āēīōūȳĀĒĪŌŪȲ]n)s", function(v) return (gsub(toNFD(v), MACRON, "") .. "t") end}, {"([cC])eps", "%1ipit"}, {"([bp])s", "%1"}, {"us", "or"}, {"s", "t"}, {"ex", "ic"}, {"x", "c"}, } function export.make_stem2(stem) local n for _, pattern in ipairs(patterns) do local key = pattern[1] stem, n = ugsub(stem, key .. "$", pattern[2]) if n > 0 then debug_track("la-utilities/" .. key) return toNFC(stem) end end debug_track("la-utilities") return stem end return export 7wnh8rnc1heuejzfoqkoo30erhm31zv ထာမ်ပလိက်:sk-IPA 10 8186 396260 15233 2026-06-03T17:09:09Z 咽頭べさ 33 396260 wikitext text/x-wiki {{#invoke:sk-pron|show}}<noinclude> {{documentation}} </noinclude> 5nizc9r9kiknkvpf0z5dqe9037tdjit ညးလွပ်:咽頭べさ/Notepad 2 9186 396197 396076 2026-06-03T12:31:51Z 咽頭べさ 33 396197 wikitext text/x-wiki [[🝴]] [[🝵]] [[🝶]] [[🝻]] [[🝼]] [[🝽]] [[🝾]] [[🝿]] [[🟙]] [[🛜]] [[🩵]] [[🩶]] [[🩷]] [[🪇]] [[🪈]] [[🪭]] [[🪮]] [[🪯]] [[🪻]] [[🪼]] [[🪽]] [[🪿]] [[🫎]] [[🫏]] [[🫚]] [[🫛]] [[🫨]] [[🫷]] [[🫸]] [[File:Omx-san̊krān.png|50x50px]] # {{l|shn|ၶိူဝ်း}} {{shn-pron|ပဵင်း-ၽဵင်ႇ}} * {{kjp-IPA|လီ}} #: {{ux|mnw|ၐြဳ ဒၞာ မိက် |t=bh}} #: {{ux|ksw|ဃိၣ်သၢရှ်ဖျၢၣ်တၢ်ဘါတရိၣ် |t=bh}} | #: {{ux|shn|ပိတ်းမၢၵ်ႇၼမ်ႉတဝ်ႈ |t=bh}} #: {{ux|my|အဲ |t=bh}} {{alt sp|th|บ้านมอญ นครสวรรค์}} * {{ur-IPA|grī}} {{der3|shn |တေ မိူဝ်း ယဝ့် ႁုး | | }} {{pi-alt|Mymr=ယဒိ လောကသန္တိံ ဣစ္ဆေယျ၊ ဗုဒ္ဓမဂ္ဂံ ဝိနာ အညော မဂ္ဂေါ နတ္ထိ။}} {{sa-alt|Deva=बकवासं त्यजतु}} {{langtrack|mnw|mkh-mmn|omx|mkh-pro|mkh-mnc-pro}} {{langtrack|mn|en|enm|ang|ine-pro|gem-pro|gmw-pro}} {{langtrack|th|shn|tai-pro|tai-swe-pro|qfa-bet-pro|aho|ar|ja|}} {{langtrack|sa|la|hi|ru|ur}} {{langtrack|so|as|it|hu|pt}} {{langtrack|zh|vi|km|lo|ko}} {{langtrack|es|sh|gmw-pro|fr|ine-pro}} {{langtrack|my|za|wa|ka|mn}} gcxm59cj813vzil4krpxw7lk1x5pc1x 396198 396197 2026-06-03T12:33:03Z 咽頭べさ 33 396198 wikitext text/x-wiki [[🝴]] [[🝵]] [[🝶]] [[🝻]] [[🝼]] [[🝽]] [[🝾]] [[🝿]] [[🟙]] [[🛜]] [[🩵]] [[🩶]] [[🩷]] [[🪇]] [[🪈]] [[🪭]] [[🪮]] [[🪯]] [[🪻]] [[🪼]] [[🪽]] [[🪿]] [[🫎]] [[🫏]] [[🫚]] [[🫛]] [[🫨]] [[🫷]] [[🫸]] [[File:Omx-san̊krān.png|50x50px]] # {{l|shn|ၶိူဝ်း}} {{shn-pron|ပဵင်း-ၽဵင်ႇ}} * {{kjp-IPA|လီ}} #: {{ux|mnw|ၐြဳ ဒၞာ မိက် |t=bh}} #: {{ux|ksw|ဃိၣ်သၢရှ်ဖျၢၣ်တၢ်ဘါတရိၣ် |t=bh}} | #: {{ux|shn|ပိတ်းမၢၵ်ႇၼမ်ႉတဝ်ႈ |t=bh}} #: {{ux|my|အဲ |t=bh}} {{alt sp|th|บ้านมอญ นครสวรรค์}} * {{ur-IPA|grī}} {{der3|shn |တေ မိူဝ်း ယဝ့် ႁုး | | }} {{pi-alt|Mymr=ယဒိ လောကသန္တိံ ဣစ္ဆေယျ၊ ဗုဒ္ဓမဂ္ဂံ ဝိနာ အညော မဂ္ဂေါ နတ္ထိ။}} {{sa-alt|Deva=किं त्वं ताडितः भवितुं न बिभेषि}} {{langtrack|mnw|mkh-mmn|omx|mkh-pro|mkh-mnc-pro}} {{langtrack|mn|en|enm|ang|ine-pro|gem-pro|gmw-pro}} {{langtrack|th|shn|tai-pro|tai-swe-pro|qfa-bet-pro|aho|ar|ja|}} {{langtrack|sa|la|hi|ru|ur}} {{langtrack|so|as|it|hu|pt}} {{langtrack|zh|vi|km|lo|ko}} {{langtrack|es|sh|gmw-pro|fr|ine-pro}} {{langtrack|my|za|wa|ka|mn}} try1jmi0cy59re4s0jj5ocjmam4hfms ကဏ္ဍ:နာမ်ဟေဲယှေန် ခရေဝ်အဝ်လ်ဂမၠိုၚ် 14 29620 396291 41328 2026-06-04T05:02:03Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:နာမ် ဟေဲယှေန် ခရေဝ်အဝ်လ်]] ဇရေင် [[ကဏ္ဍ:နာမ်ဟေဲယှေန် ခရေဝ်အဝ်လ်ဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင် 41328 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာဟေဲယှေန် ခရေဝ်အဝ်လ်]] i22emcnzn5geiuhbn215axayhexl820 မဝ်ဂျူ:UnitTests 828 37302 396212 294281 2026-06-03T13:44:57Z 咽頭べさ 33 396212 Scribunto text/plain local UnitTester = {} local require = require local concat = table.concat local deep_equals = require("Module:table/deepEquals") local error = error local explode_utf8 = require("Module:string utilities").explode_utf8 local find = string.find local full_url = mw.uri.fullUrl local gsub = string.gsub local html = mw.html local insert = table.insert local ipairs = ipairs local is_callable = require("Module:fun/isCallable") local is_combining = require("Module:Unicode data").is_combining local match = string.match local nowiki = require("Module:string/nowiki") local pairs = pairs local shallow_copy = require("Module:table/shallowCopy") local sort = table.sort local sorted_pairs = require("Module:table/sortedPairs") local sub = string.sub local tostring = tostring local traceback = debug.traceback local type = type local umatch = mw.ustring.find local unpack = unpack or table.unpack -- Lua 5.2 compatibility local usub = mw.ustring.sub local xpcall = require("Module:fun/xpcall") -- DO NOT replace with mw.loadData("Module:headword/data").pagename as we need the root portion local current_title = mw.title.getCurrentTitle() local tick, cross = '[[File:Yes check.svg|20px|alt=Passed|link=|Test passed]]', '[[File:X mark.svg|20px|alt=Failed|link=|Test failed]]' local function first_difference(s1, s2) if not (type(s1) == "string" and type(s2) == "string") then return "N/A" elseif s1 == s2 then return "" end s1 = explode_utf8(s1) s2 = explode_utf8(s2) local i = 0 repeat i = i + 1 until s1[i] ~= s2[i] return i end local function highlight(str) if umatch(str, "%s") then return '<span style="background-color: var(--wikt-palette-red-4,pink);">' .. gsub(str, " ", "&nbsp;") .. '</span>' else return '<span style="color: var(--wikt-palette-red-9, red);">' .. str .. '</span>' end end local function find_noncombining(str, i, incr) while true do local ch = usub(str, i, i) if ch == "" or not is_combining(ch) then return i end i = i + incr end end -- Highlight character where a difference was found. Start highlight at first -- non-combining character before the position. End it after the first non- -- combining characters after the position. Can specify a custom highlighing -- function. local function highlight_difference(actual, expected, differs_at, func) if type(differs_at) ~= "number" or not (actual and expected) then return actual end differs_at = find_noncombining(expected, differs_at, -1) local i = find_noncombining(actual, differs_at, -1) local j = find_noncombining(actual, differs_at + 1, 1) j = j - 1 return usub(actual, 1, i - 1) .. (is_callable(func) and func or highlight)(usub(actual, i, j)) .. usub(actual, j + 1, -1) end local function val_to_str(v) if type(v) == "string" then v = gsub(v, '\n', '\\n') if find(gsub(v, '[^\'"]', ''), '^"+$') then return "'" .. v .. "'" end return '"' .. gsub(v, '"', '\\"' ) .. '"' elseif type(v) == 'table' then local result, done = {}, {} for k, val in ipairs(v) do insert(result, val_to_str(val)) done[k] = true end for k, val in sorted_pairs(v) do if not done[k] then if (type(k) ~= "string") or not find(k, '^[_%a][_%a%d]*$') then k = '[' .. val_to_str(k) .. ']' end insert(result, k .. '=' .. val_to_str(val)) end end return "{" .. concat(result, ", ") .. "}" else return tostring(v) end end local function insert_differences(keys, t1, t2) for k, v1 in pairs(t1) do local v2 = t2[k] if v2 == nil or not deep_equals(v1, v2, true) then insert(keys, k) end end end local function get_differing_keys(t1, t2) local ty1 = type(t1) if not (ty1 == type(t2) and ty1 == "table") then return nil end local keys = {} insert_differences(keys, t1, t2) insert_differences(keys, t2, t1) return keys end local function extract_keys(t, keys) if not keys then return t end local new_t = {} for _, key in ipairs(keys) do new_t[key] = t[key] end return new_t end -- Return the header for the result table along with the number of columns in the table. function UnitTester:new_result_table() local header_row = html.create("tr") :tag("th") :attr("class", "unit-tests-img-corner") :css("cursor", "pointer") :attr("title", "Only failed tests") :done() local columns = shallow_copy(self.name_columns) insert(columns, "Expected") insert(columns, "Actual") if self.differs_at then insert(columns, "Differs at") end if self.comments then insert(columns, "Comments") end for _, cell in ipairs(columns) do header_row = header_row:tag("th") :wikitext(cell) :done() end self.columns = #columns + 1 return html.create("table") :attr("class", "unit-tests wikitable") :node(header_row) end function UnitTester:get_result(key) return self[key](self) end function UnitTester:display_difference(success, name, actual, expected, options) local differs_at = self.differs_at and first_difference(expected, actual) local comment = self.comments and (options and options.comment or "") expected = expected == nil and "(nil)" or tostring(expected) actual = actual == nil and "(nil)" or tostring(actual) if self.nowiki or options and options.nowiki then expected = nowiki(expected) actual = nowiki(actual) end if options and is_callable(options.display) then expected = options.display(expected) actual = options.display(actual) end local cells if type(name) == "table" then cells = shallow_copy(name) insert(cells, expected) insert(cells, actual) insert(cells, differs_at) else cells = { name, expected, actual, differs_at } end insert(cells, comment) -- In case differs_at is nil. local row = html.create("tr") if success then row = row:attr("class", "unit-test-pass") insert(cells, 1, tick) else row = row:attr("class", "unit-test-fail") insert(cells, 1, cross) self.num_failures = self.num_failures + 1 end for _, cell in ipairs(cells) do row = row:tag("td") :wikitext(cell) :done() end self.result_table = self.result_table:node(row) self.total_tests = self.total_tests + 1 end function UnitTester:equals(name, actual, expected, options) local success = actual == expected if options and options.show_difference then local difference = first_difference(expected, actual) if type(difference) == "number" then actual = highlight_difference(actual, expected, difference, is_callable(options.show_difference) and options.show_difference) end end self:display_difference(success, name, actual, expected, options) end function UnitTester:preprocess_equals(text, expected, options) local actual = self.frame:preprocess(text) self:equals(nowiki(text), actual, expected, options) end function UnitTester:preprocess_equals_many(prefix, suffix, cases, options) for _, case in ipairs(cases) do self:preprocess_equals(prefix .. case[1] .. suffix, case[2], options) end end function UnitTester:preprocess_equals_preprocess(text1, text2, options) local expected = self.frame:preprocess(text2) self:preprocess_equals(text1, expected, options) end function UnitTester:preprocess_equals_preprocess_many(prefix1, suffix1, prefix2, suffix2, cases, options) for _, case in ipairs(cases) do self:preprocess_equals_preprocess(prefix1 .. case[1] .. suffix1, prefix2 .. (case[2] and case[2] or case[1]) .. suffix2, options) end end function UnitTester:equals_deep(name, actual, expected, options) local actual_str, expected_str local success = deep_equals(actual, expected, true) if success then if options and options.show_table_difference then actual_str = '' expected_str = '' end else if options and options.show_table_difference then local keys = get_differing_keys(actual, expected) actual_str = val_to_str(extract_keys(actual, keys)) expected_str = val_to_str(extract_keys(expected, keys)) end end if (not options) or not options.show_table_difference then actual_str = val_to_str(actual) expected_str = val_to_str(expected) end self:display_difference(success, name, actual_str, expected_str, options) end function UnitTester:iterate(examples, func) require 'libraryUtil'.checkType('iterate', 1, examples, 'table') if type(func) == "string" then func = self[func] elseif not is_callable(func) then error(("bad argument #2 to 'iterate' (expected function, callable table or string; got %s)") :format(type(func)), 2) end for i, example in ipairs(examples) do if type(example) == 'table' then func(self, unpack(example)) elseif type(example) == 'string' then self:header(example) else error(('bad example #%d (expected table or string, got %s)') :format(i, type(example)), 2) end end end function UnitTester:header(text) local prefix, maintext = match(text, '^#(h[0-9]+):(.*)$') if not prefix then maintext = text end local header = html.create("th") :attr("colspan", self.columns) if prefix == "h1" then header = header:css("text-align", "center") :css("font-size", "150%") else header = header:css("text-align", "left") end header = header:wikitext(maintext) self.result_table = self.result_table:tag("tr") :node(header) :done() end local function err_handler(mesg) return {mesg = mesg, traceback = traceback("", 2)} end function UnitTester:run(frame) self.num_failures = 0 local output = {} local boolean = {type = "boolean"} local iargs = require("Module:parameters").process(frame.args, { ["nowiki"] = boolean, ["differs_at"] = boolean, ["comments"] = boolean, ["summarize"] = boolean, ["name_column"] = {list = true, default = "Text"}, }) self.frame = frame self.nowiki = iargs.nowiki self.differs_at = iargs.differs_at self.comments = iargs.comments self.summarize = iargs.summarize self.name_columns = iargs.name_column self.total_tests = 0 -- Sort results into alphabetical order. local self_sorted = {} for key in pairs(self) do if sub(key, 1, 4) == "test" then insert(self_sorted, key) end end sort(self_sorted) -- Add results to the results table. for _, key in ipairs(self_sorted) do self.result_table = self:new_result_table() :tag("caption") :css("text-align", "left") :css("font-weight", "bold") :wikitext(key .. ":") :done() local success, err = xpcall(UnitTester.get_result, err_handler, self, key) if not success then self.result_table = self.result_table:tag("tr") :tag("td") :attr("colspan", self.columns) :css("text-align", "left") :tag("strong") :attr("class", "error") :wikitext("Script error during testing: " .. nowiki(err.mesg)) :done() :wikitext(frame:extensionTag("pre", err.traceback or "(no traceback)")) :allDone() self.num_failures = self.num_failures + 1 end insert(output, tostring(self.result_table)) end local refresh_link = tostring(full_url(current_title.fullText, 'action=purge&forcelinkupdate=1')) local failure_cat = '[[Category:Failing testcase modules]]' if sub(current_title.text, -14) == "/documentation" then failure_cat = '' end local num_successes = self.total_tests - self.num_failures if self.summarize then if self.num_failures == 0 then return '<strong class="success">' .. self.total_tests .. '/' .. self.total_tests .. ' tests passed</strong>' else return '<strong class="error">' .. num_successes .. '/' .. self.total_tests .. ' tests passed</strong>' end else return (self.num_failures == 0 and '<strong class="success">All tests passed.</strong>' or '<strong class="error">' .. self.num_failures .. ' of ' .. self.total_tests .. ' test' .. (self.total_tests == 1 and '' or 's' ) .. ' failed.</strong>' .. failure_cat) .. " <span class='plainlinks unit-tests-refresh'>[" .. refresh_link .. " (refresh)]</span>\n\n" .. concat(output, "\n\n") end end function UnitTester:new() local o = {} setmetatable(o, self) self.__index = self return o end local unit_tester = UnitTester:new() function unit_tester.run_tests(frame) return unit_tester:run(frame) end return unit_tester 6hvi0gplwylahhtzxlz8c1gbn658d2d ထာမ်ပလိက်:da-decl 10 52011 396250 68073 2026-06-03T16:52:43Z 咽頭べさ 33 396250 wikitext text/x-wiki {{#invoke:checkparams|warn}}<!-- Validate template parameters -->{{da-noun-infl{{#switch:{{{n|}}}|sg=-unc|pl=-pl}}-base<!-- -->|g={{#if:{{{g|}}}|{{{g}}}|<!-- -->{{#switch:{{{1}}}<!-- -->|en|n=c<!-- -->|et|t=n<!-- -->|#default=လိၚ်<br />ပွမဗၠေတ်<!-- -->}}}}<!-- ကိုန်ဨကဝုစ် -->|sg-indef=<!-- -->{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}<!-- -->|sg-def=<!-- -->{{#switch:{{{1}}}<!-- -->|en|n|et|t={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{1}}}<!-- -->|#default={{{1}}}<!-- -->}}<!-- -->|sg-def-2=<!-- -->{{{sg-def-2|}}}<!-- -->{{#if:{{{dc|}}}|{{#ifeq:{{{dc}}}|1| }}}}<!-- ကိုန်ဗဟုဝစ် -->|pl-indef=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}<!-- -->|s={{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}{{{2}}}<!-- -->|#default={{#if:{{{2|}}}|{{{2}}}|{{{base|{{pagename}}}}}}}<!-- -->}}<!-- -->|pl-indef-2=<!-- -->{{{pl-indef-2|}}}<!-- -->|pl-indef-3=<!-- -->{{{pl-indef-3|}}}<!-- -->|pl-def=<!-- -->{{#switch:{{{3|}}}<!-- -->|ne=<!-- -->{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}ne<!-- -->|=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}ne<!-- -->|s={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{{2}}}ene<!-- -->|#default={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}ene<!-- -->}}<!-- -->|#default=<!-- -->{{{3}}}<!-- -->}}<!-- -->|pl-def-2=<!-- -->{{{pl-def-2|}}}<!-- -->|pl-def-3=<!-- -->{{{pl-def-3|}}}<!-- ဗဳဇဂကူကိုန်ဨကဝုစ် -->|gen-sg-indef=<!-- -->{{#ifeq:{{{4}}}|'|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}'|{{#if:{{{4|}}}|{{{4}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}s}}}}<!-- -->|gen-sg-indef-2=<!-- -->{{{gen-sg-indef-2|}}}<!-- -->|gen-sg-indef-3=<!-- -->{{{gen-sg-indef-3|}}}<!-- -->|gen-sg-def=<!-- -->{{#switch:{{{1}}}<!-- -->|en|n|et|t={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{1}}}s<!-- -->|#default={{#if:{{{5|}}}|{{{5}}}|{{{1}}}s}}<!-- -->}}<!-- -->|gen-sg-def-2=<!-- -->{{#if:{{{gen-sg-def-2|}}}|{{{gen-sg-def-2}}}|{{#if:{{{sg-def-2|}}}|{{{sg-def-2}}}s}}}}<!-- ဗဳဇဂကူကိုန်ဗဟုဝစ် -->|gen-pl-indef=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}s<!-- -->|s={{{base|{{pagename}}}}}s'<!-- -->|#default={{#if:{{{6|}}}|{{{6}}}|{{#if:{{{2|}}}|{{{2}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}s}}<!-- -->}}<!-- -->|gen-pl-indef-2=<!-- -->{{#if:{{{gen-pl-indef-2|}}}|{{{gen-pl-indef-2}}}|{{#if:{{{pl-indef-2|}}}|{{{pl-indef-2}}}s}}}}<!-- -->|gen-pl-def=<!-- -->{{#ifeq:{{{3|}}}|ne<!-- -->|<!-- -->{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}nes<!-- -->|<!-- -->{{#if:{{{7|}}}<!-- -->|<!-- -->{{{7}}}<!-- -->|<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}nes<!-- -->|s={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{{2}}}enes<!-- -->|#default={{#if:{{{3|}}}|{{{3}}}s|{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}enes}}<!-- -->}}<!-- -->}}<!-- -->}}<!-- -->|gen-pl-def-2=<!-- -->{{#if:{{{gen-pl-def-2|}}}|{{{gen-pl-def-2}}}|{{#if:{{{pl-def-2|}}}|{{{pl-def-2}}}s}}}}<!-- -->|gen-pl-def-3=<!-- -->{{#if:{{{gen-pl-def-3|}}}|{{{gen-pl-def-3}}}|{{#if:{{{pl-def-3|}}}|{{{pl-def-3}}}s}}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> d88a2tb79j0ngqnz2ma739zrkpp7mo4 396251 396250 2026-06-03T16:53:03Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:da-noun-infl]] ဇရေင် [[ထာမ်ပလိက်:da-decl]] 396250 wikitext text/x-wiki {{#invoke:checkparams|warn}}<!-- Validate template parameters -->{{da-noun-infl{{#switch:{{{n|}}}|sg=-unc|pl=-pl}}-base<!-- -->|g={{#if:{{{g|}}}|{{{g}}}|<!-- -->{{#switch:{{{1}}}<!-- -->|en|n=c<!-- -->|et|t=n<!-- -->|#default=လိၚ်<br />ပွမဗၠေတ်<!-- -->}}}}<!-- ကိုန်ဨကဝုစ် -->|sg-indef=<!-- -->{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}<!-- -->|sg-def=<!-- -->{{#switch:{{{1}}}<!-- -->|en|n|et|t={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{1}}}<!-- -->|#default={{{1}}}<!-- -->}}<!-- -->|sg-def-2=<!-- -->{{{sg-def-2|}}}<!-- -->{{#if:{{{dc|}}}|{{#ifeq:{{{dc}}}|1| }}}}<!-- ကိုန်ဗဟုဝစ် -->|pl-indef=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}<!-- -->|s={{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}{{{2}}}<!-- -->|#default={{#if:{{{2|}}}|{{{2}}}|{{{base|{{pagename}}}}}}}<!-- -->}}<!-- -->|pl-indef-2=<!-- -->{{{pl-indef-2|}}}<!-- -->|pl-indef-3=<!-- -->{{{pl-indef-3|}}}<!-- -->|pl-def=<!-- -->{{#switch:{{{3|}}}<!-- -->|ne=<!-- -->{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}ne<!-- -->|=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}ne<!-- -->|s={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{{2}}}ene<!-- -->|#default={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}ene<!-- -->}}<!-- -->|#default=<!-- -->{{{3}}}<!-- -->}}<!-- -->|pl-def-2=<!-- -->{{{pl-def-2|}}}<!-- -->|pl-def-3=<!-- -->{{{pl-def-3|}}}<!-- ဗဳဇဂကူကိုန်ဨကဝုစ် -->|gen-sg-indef=<!-- -->{{#ifeq:{{{4}}}|'|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}'|{{#if:{{{4|}}}|{{{4}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}s}}}}<!-- -->|gen-sg-indef-2=<!-- -->{{{gen-sg-indef-2|}}}<!-- -->|gen-sg-indef-3=<!-- -->{{{gen-sg-indef-3|}}}<!-- -->|gen-sg-def=<!-- -->{{#switch:{{{1}}}<!-- -->|en|n|et|t={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{1}}}s<!-- -->|#default={{#if:{{{5|}}}|{{{5}}}|{{{1}}}s}}<!-- -->}}<!-- -->|gen-sg-def-2=<!-- -->{{#if:{{{gen-sg-def-2|}}}|{{{gen-sg-def-2}}}|{{#if:{{{sg-def-2|}}}|{{{sg-def-2}}}s}}}}<!-- ဗဳဇဂကူကိုန်ဗဟုဝစ် -->|gen-pl-indef=<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}s<!-- -->|s={{{base|{{pagename}}}}}s'<!-- -->|#default={{#if:{{{6|}}}|{{{6}}}|{{#if:{{{2|}}}|{{{2}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}s}}<!-- -->}}<!-- -->|gen-pl-indef-2=<!-- -->{{#if:{{{gen-pl-indef-2|}}}|{{{gen-pl-indef-2}}}|{{#if:{{{pl-indef-2|}}}|{{{pl-indef-2}}}s}}}}<!-- -->|gen-pl-def=<!-- -->{{#ifeq:{{{3|}}}|ne<!-- -->|<!-- -->{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}nes<!-- -->|<!-- -->{{#if:{{{7|}}}<!-- -->|<!-- -->{{{7}}}<!-- -->|<!-- -->{{#switch:{{{2}}}<!-- -->|e|r|er={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}{{{2}}}nes<!-- -->|s={{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{{2}}}enes<!-- -->|#default={{#if:{{{3|}}}|{{{3}}}s|{{#if:{{{stem|}}}|{{{stem}}}|{{#if:{{{base|}}}|{{{base}}}|{{pagename}}}}}}{{#if:{{{dc|}}}|{{#invoke:string/templates|pos|{{pagename}}|-1}}}}enes}}<!-- -->}}<!-- -->}}<!-- -->}}<!-- -->|gen-pl-def-2=<!-- -->{{#if:{{{gen-pl-def-2|}}}|{{{gen-pl-def-2}}}|{{#if:{{{pl-def-2|}}}|{{{pl-def-2}}}s}}}}<!-- -->|gen-pl-def-3=<!-- -->{{#if:{{{gen-pl-def-3|}}}|{{{gen-pl-def-3}}}|{{#if:{{{pl-def-3|}}}|{{{pl-def-3}}}s}}}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> d88a2tb79j0ngqnz2ma739zrkpp7mo4 ထာမ်ပလိက်:module documentation 10 58143 396275 75797 2026-06-04T04:16:38Z 咽頭べさ 33 396275 wikitext text/x-wiki <includeonly>{{#invoke:module documentation|show}}</includeonly><noinclude>ဗဵုရံၚ် [[Module:module documentation]] သွက်မရပ်စပ်ထာမ်ပလိက်တဏအ်။[[Category:ထာမ်ပလိက်စရၚ်မချူသမ္တီလဝ်ဂမၠိုၚ်]]</noinclude> 2eiqsjs4rivkz8r2dijhjh15jfb0jlj ထာမ်ပလိက်:label language-specific data documentation 10 71677 396217 94353 2026-06-03T14:14:17Z 咽頭べさ 33 396217 wikitext text/x-wiki မဝ်ဂျူတဏအ်ဝွံဒေတာလုပ်အဝေါၚ်သွက်ပရေၚ်မစၟတ်သမ္တီအရေဝ်ဘာသာချိုတ်ချိုတ်ပၠိုတ်ပၠိုတ်<includeonly> သွက် {{#invoke:languages/templates|getByCode|{{SUBPAGENAME}}|makeCategoryLink|true}}</includeonly>။ ဗဵုရံၚ် [[Module:labels/data]] သွက်ပဵုနူအပ္ဍဲဂှ်။<!-- --><noinclude>{{documentation}}</noinclude> saqdvap76qqq30r6mrwuw4czy55ftov မဝ်ဂျူ:labels/data/lang/pl 828 110457 396216 394108 2026-06-03T14:07:29Z 咽頭べさ 33 396216 Scribunto text/plain local labels = {} -- Greater Poland dialects labels["Greater Poland"] = { aliases = {"Wielkopolska"}, Wikipedia = "Greater Poland dialect group", regional_categories = true, parent = true, } labels["Kociewie"] = { Wikipedia = "Kociewie dialect", regional_categories = true, parent = "Greater Poland", } labels["Bory Tucholskie"] = { aliases = {"Tuchola Forest"}, Wikipedia = "Bory Tucholskie dialect", regional_categories = true, parent = "Greater Poland", } labels["Krajna"] = { Wikipedia = "Krajna dialect", regional_categories = true, parent = "Greater Poland", } labels["Chełmno-Dobrzyń"] = { aliases = {"CD", "Chełmińsko-Dobrzyńska"}, Wikipedia = "en:Chełmno-Dobrzyń dialect", display = "ချေလ်မ်နဝ်-ဒဝ်ဗဇေၚ်", regional_categories = "ချေလ်မ်နဝ်-ဒဝ်ဗဇေၚ်", parent = "Greater Poland", } labels["Chełmno"] = { Wikipedia = "en:Chełmno-Dobrzyń dialect", display = "ချေလ်မ်နဝ်", regional_categories = "ချေလ်မ်နဝ်", parent = "Chełmno-Dobrzyń", } labels["Dobrzyń"] = { aliases = {"Dobrzyn"}, Wikipedia = "Chełmno-Dobrzyń dialect", regional_categories = true, parent = "Chełmno-Dobrzyń", } labels["Kuyavia"] = { aliases = {"Cuyavia", "Kujawy"}, Wikipedia = "en:Kuyavian dialect", display = "ကူယျာဝဳယာန်", regional_categories = "ကူယျာဝဳယာန်", parent = "Greater Poland", } labels["Northern Greater Poland"] = { Wikipedia = "Northern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Western Greater Poland"] = { Wikipedia = "Western Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Central Greater Poland"] = { Wikipedia = "Central Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Eastern Greater Poland"] = { Wikipedia = "Eastern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Southern Greater Poland"] = { Wikipedia = "Southern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Wieleń"] = { aliases = {"Wielen"}, Wikipedia = true, regional_categories = true, parent = "Northern Greater Poland", } labels["Poznań"] = { aliases = {"Poznan"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "Central Greater Poland", } -- Masovian dialects labels["Masovia"] = { aliases = {"Mazowsze"}, Wikipedia = "Masovian dialect group", regional_categories = "Masovian", parent = true, } labels["Lubawa"] = { Wikipedia = "Lubawa dialect", regional_categories = true, regional_categories = true, parent = "Masovia", } labels["Ostróda"] = { aliases = {"Ostroda"}, Wikipedia = "Ostróda dialect", regional_categories = true, parent = "Masovia", } labels["Masuria"] = { aliases = {"Mazuria", "Mazury", "Masurian"}, Wikipedia = "Masurian dialects", regional_categories = true, parent = "Masovia", } labels["Warmia"] = { Wikipedia = "Warmia dialect", regional_categories = true, parent = "Masovia", } labels["Suwałki"] = { aliases = {"Suwalki"}, Wikipedia = "Suwałki dialect", regional_categories = true, parent = "Masovia", } labels["Łowicz"] = { aliases = {"Lowicz"}, Wikipedia = "Łowicz dialect", regional_categories = true, parent = "Masovia", } labels["Near Masovian"] = { aliases = {"Near Masovia", "Near Mazovia", "Near Mazovian"}, region = "the {{w|Near Masovian dialect}}", Wikipedia = "Near Masovian dialect", regional_categories = true, parent = "Masovia", } labels["Far Masovian"] = { aliases = {"Far Masovia", "Far Mazovia", "Far Mazovian"}, region = "the {{w|Far Masovian dialect}}", Wikipedia = "en:Far Masovian dialect", display = "ဖှာ မာသဝ်ဝဳယာန်", regional_categories = "ဖှာ မာသဝ်ဝဳယာန်", parent = "Masovia", } labels["Kurpie"] = { Wikipedia = "Kurpie dialect", regional_categories = true, parent = "Masovia", } labels["Podlachia"] = { aliases = {"Podlasie", "Podlachian"}, Wikipedia = "Podlachian dialect", regional_categories = true, parent = "Masovia", } labels["Białystok"] = { aliases = {"Bialystok"}, Wikipedia = "Bialystok dialect", regional_categories = {true, "Urban"}, parent = "Podlachia", } labels["Warsaw"] = { aliases = {"Warszawa"}, Wikipedia = "Warsaw dialect", regional_categories = {true, "Urban"}, parent = "Near Masovian", } -- Lesser Poland dialects labels["Lesser Poland"] = { Wikipedia = "Lesser Poland dialect group", regional_categories = true, parent = true, } labels["Łęczyca"] = { aliases = {"Leczyca"}, Wikipedia = "Łęczyca dialect", regional_categories = true, parent = "Lesser Poland", } labels["Sieradz"] = { Wikipedia = "Sieradz dialect", regional_categories = true, parent = "Lesser Poland", } labels["Masovian Borderland"] = { Wikipedia = "Masovian Borderland dialect", regional_categories = true, parent = "Lesser Poland", } labels["Kielce"] = { Wikipedia = "Kielce dialect", regional_categories = true, parent = "Lesser Poland", } labels["Lasovia"] = { Wikipedia = "Lasovia dialect", regional_categories = true, parent = "Lesser Poland", } labels["Eastern Kraków"] = { aliases = {"Eastern Krakow"}, Wikipedia = "Eastern Kraków dialect", regional_categories = true, parent = "Lesser Poland", } labels["Western Kraków"] = { aliases = {"Western Krakow"}, Wikipedia = "Kraków dialect", regional_categories = true, parent = "Lesser Poland", } labels["Lach"] = { Wikipedia = "Sącz Lachs", regional_categories = true, parent = "Lesser Poland", } labels["Podegrodzie"] = { aliases = {"Sącz Lach"}, Wikipedia = "Podegrodzie dialect", regional_categories = true, parent = "Lach", } labels["Limanowa"] = { regional_categories = true, parent = "Lach", } labels["Western Lublin"] = { Wikipedia = "Western Lublin dialect", regional_categories = true, parent = "Lesser Poland", } labels["Eastern Lublin"] = { Wikipedia = "Eastern Lublin dialect", regional_categories = true, parent = "Lesser Poland", } labels["Przemyśl"] = { aliases = {"Przemysl"}, Wikipedia = "Przemyśl dialect", regional_categories = true, parent = "Lesser Poland", } labels["Biecz"] = { Wikipedia = "Biecz dialect", regional_categories = true, parent = "Lesser Poland", } labels["Kraków"] = { aliases = {"Krakow", "Cracow"}, Wikipedia = "Kraków", regional_categories = {true, "Urban"}, parent = "Western Kraków", } labels["Lublin"] = { Wikipedia = true, regional_categories = true, regional_categories = {true, "Urban"}, parent = "Western Lublin", } labels["Łódź"] = { aliases = {"Lodz"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "Łęczyca", } labels["Lviv"] = { aliases = {"Lwów", "Lwow"}, Wikipedia = "Lwów dialect", regional_categories = {true, "Urban"}, parent = "Southern Borderlands", } labels["Goral"] = { aliases = {"Góral"}, Wikipedia = "Goral ethnolect", regional_categories = true, parent = "Lesser Poland", } labels["Podhale"] = { Wikipedia = "Podhale dialect", regional_categories = true, parent = "Goral", } labels["Babia Góra"] = { aliases = {"Babia Gora"}, Wikipedia = "Babia Góra dialect", regional_categories = true, parent = "Goral", } labels["Pieniny"] = { Wikipedia = "Pieniny dialect", regional_categories = true, parent = "Goral", } labels["Łącko"] = { Wikipedia = "Łącko dialect", aliases = {"Lacko"}, regional_categories = true, parent = "Goral", } labels["Piwniczna"] = { Wikipedia = "Piwniczna dialect", regional_categories = true, parent = "Goral", } labels["Kliszczak"] = { Wikipedia = "Kliszczak dialect", regional_categories = true, parent = "Goral", } labels["Żywiec"] = { aliases = {"Zywiec"}, Wikipedia = "Żywiec dialect", regional_categories = true, parent = "Goral", } labels["Orawa"] = { aliases = {"Orava"}, Wikipedia = "Orawa dialect", regional_categories = true, parent = "Goral", } labels["Spisz"] = { Wikipedia = "Spisz dialect", regional_categories = true, parent = "Goral", } labels["Zagórze"] = { Wikipedia = "Zagórze dialect", regional_categories = true, parent = "Goral", } labels["Kysuce"] = { regional_categories = true, parent = "Goral", } labels["Ochotnica"] = { regional_categories = true, parent = "Goral", } labels["Liptov"] = { regional_categories = true, parent = "Goral", } labels["Bukovina"] = { aliases = {"Bucovina", "Bukovinian", "Bukowina"}, Wikipedia = "Bukovinian Polish dialect", regional_categories = true, parent = "Goral", } -- Borderlands dialects labels["Borderlands"] = { aliases = {"Kresy"}, Wikipedia = "Kresy", regional_categories = true, parent = true, } labels["Northern Borderlands"] = { aliases = {"północnokresowy"}, Wikipedia = "Northern Borderlands dialect", regional_categories = true, parent = "Borderlands", } labels["Southern Borderlands"] = { aliases = {"południowokresowy"}, Wikipedia = "Southern Borderlands dialect", regional_categories = true, parent = "Borderlands", } labels["Vilnius"] = { aliases = {"Vilna", "Wilno"}, Wikipedia = true, regional_categories = {true, "Urban", "Northern Borderlands"}, parent = "Northern Borderlands", } -- New mixed dialects labels["New mixed dialects"] = { alias = {"New Mixed Dialects"}, Wikidata = "Q4326522", regional_categories = "New Mixed Dialects", parent = true, } labels["Wrocław"] = { aliases = {"Wroclaw"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "New mixed dialects", } labels["Lower Silesia"] = { Wikipedia = true, regional_categories = true, parent = "New mixed dialects", } labels["Malbork"] = { Wikipedia = "Kociewie dialect", regional_categories = true, parent = "Kociewie", } labels["Polish People's Republic"] = { aliases = {"PRL", "PPR"}, Wikipedia = true, topical_categories = true, } -- Historic lables labels["Middle Polish"] = { aliases = {"średniopolski"}, Wikipedia = "en:Middle Polish", display = "ပဝ်လာန်လဒေါဝ်", plain_categories = "ပဝ်လာန်လဒေါဝ်", } labels["pl-pre-1816"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၁၈၁၆)", Wikipedia = "en:History_of_Polish_orthography#19th_century", } labels["pl-pre-1936"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၁၉၃၆)", Wikipedia = "en:History_of_Polish_orthography#1936_reform", } labels["pl-pre-2026"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၂၀၂၆)", Wikipedia = "en:History_of_Polish_orthography#2026_reform", } -- Grammatical labels labels["reflexive-się"] = { aliases = {"reflexive-sie"}, display = "[[Appendix:Glossary#reflexive|reflexive]] with {{m|pl|się}}", pos_categories = "reflexive verbs", } labels["reflexive-sobie"] = { display = "[[Appendix:Glossary#reflexive|reflexive]] with {{m|pl|sobie}}", pos_categories = "reflexive verbs", } labels["Wieluń"] = { display = "လဳလောန်", } labels["Radomsko"] = { display = "ရာဒေါန်သကဝ်", } return require("Module:labels").finalize_data(labels) n3iyuw2ecgd0zkkinc9cm44tdny6w4z 396218 396216 2026-06-03T14:17:28Z 咽頭べさ 33 396218 Scribunto text/plain local labels = {} -- Greater Poland dialects labels["Greater Poland"] = { aliases = {"Wielkopolska"}, Wikipedia = "Greater Poland dialect group", regional_categories = true, parent = true, } labels["Kociewie"] = { Wikipedia = "Kociewie dialect", regional_categories = true, parent = "Greater Poland", } labels["Bory Tucholskie"] = { aliases = {"Tuchola Forest"}, Wikipedia = "Bory Tucholskie dialect", regional_categories = true, parent = "Greater Poland", } labels["Krajna"] = { Wikipedia = "Krajna dialect", regional_categories = true, parent = "Greater Poland", } labels["Chełmno-Dobrzyń"] = { aliases = {"CD", "Chełmińsko-Dobrzyńska"}, Wikipedia = "en:Chełmno-Dobrzyń dialect", display = "ချေလ်မ်နဝ်-ဒဝ်ဗဇေၚ်", regional_categories = "ချေလ်မ်နဝ်-ဒဝ်ဗဇေၚ်", parent = "Greater Poland", } labels["Chełmno"] = { Wikipedia = "en:Chełmno-Dobrzyń dialect", display = "ချေလ်မ်နဝ်", regional_categories = "ချေလ်မ်နဝ်", parent = "Chełmno-Dobrzyń", } labels["Dobrzyń"] = { aliases = {"Dobrzyn"}, Wikipedia = "Chełmno-Dobrzyń dialect", regional_categories = true, parent = "Chełmno-Dobrzyń", } labels["Kuyavia"] = { aliases = {"Cuyavia", "Kujawy"}, Wikipedia = "en:Kuyavian dialect", display = "ကူယျာဝဳယာန်", regional_categories = "ကူယျာဝဳယာန်", parent = "Greater Poland", } labels["Northern Greater Poland"] = { Wikipedia = "Northern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Western Greater Poland"] = { Wikipedia = "Western Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Central Greater Poland"] = { Wikipedia = "Central Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Eastern Greater Poland"] = { Wikipedia = "Eastern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Southern Greater Poland"] = { Wikipedia = "Southern Greater Poland dialect", regional_categories = true, parent = "Greater Poland", } labels["Wieleń"] = { aliases = {"Wielen"}, Wikipedia = true, regional_categories = true, parent = "Northern Greater Poland", } labels["Poznań"] = { aliases = {"Poznan"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "Central Greater Poland", } -- Masovian dialects labels["Masovia"] = { aliases = {"Mazowsze"}, Wikipedia = "Masovian dialect group", regional_categories = "Masovian", parent = true, } labels["Lubawa"] = { Wikipedia = "Lubawa dialect", regional_categories = true, regional_categories = true, parent = "Masovia", } labels["Ostróda"] = { aliases = {"Ostroda"}, Wikipedia = "Ostróda dialect", regional_categories = true, parent = "Masovia", } labels["Masuria"] = { aliases = {"Mazuria", "Mazury", "Masurian"}, Wikipedia = "Masurian dialects", regional_categories = true, parent = "Masovia", } labels["Warmia"] = { Wikipedia = "Warmia dialect", regional_categories = true, parent = "Masovia", } labels["Suwałki"] = { aliases = {"Suwalki"}, Wikipedia = "Suwałki dialect", regional_categories = true, parent = "Masovia", } labels["Łowicz"] = { aliases = {"Lowicz"}, Wikipedia = "Łowicz dialect", regional_categories = true, parent = "Masovia", } labels["Near Masovian"] = { aliases = {"Near Masovia", "Near Mazovia", "Near Mazovian"}, region = "the {{w|Near Masovian dialect}}", Wikipedia = "Near Masovian dialect", regional_categories = true, parent = "Masovia", } labels["Far Masovian"] = { aliases = {"Far Masovia", "Far Mazovia", "Far Mazovian"}, region = "the {{w|Far Masovian dialect}}", Wikipedia = "en:Far Masovian dialect", display = "ဖှာ မာသဝ်ဝဳယာန်", regional_categories = "ဖှာ မာသဝ်ဝဳယာန်", parent = "Masovia", } labels["Kurpie"] = { Wikipedia = "Kurpie dialect", regional_categories = true, parent = "Masovia", } labels["Podlachia"] = { aliases = {"Podlasie", "Podlachian"}, Wikipedia = "Podlachian dialect", regional_categories = true, parent = "Masovia", } labels["Białystok"] = { aliases = {"Bialystok"}, Wikipedia = "Bialystok dialect", regional_categories = {true, "Urban"}, parent = "Podlachia", } labels["Warsaw"] = { aliases = {"Warszawa"}, Wikipedia = "Warsaw dialect", regional_categories = {true, "Urban"}, parent = "Near Masovian", } -- Lesser Poland dialects labels["Lesser Poland"] = { Wikipedia = "Lesser Poland dialect group", regional_categories = true, parent = true, } labels["Łęczyca"] = { aliases = {"Leczyca"}, Wikipedia = "Łęczyca dialect", regional_categories = true, parent = "Lesser Poland", } labels["Sieradz"] = { Wikipedia = "en:Sieradz dialect", display = "သဳရာဒ်ဇ်", regional_categories = "သဳရာဒ်ဇ်", parent = "Lesser Poland", } labels["Masovian Borderland"] = { Wikipedia = "Masovian Borderland dialect", regional_categories = true, parent = "Lesser Poland", } labels["Kielce"] = { Wikipedia = "Kielce dialect", regional_categories = true, parent = "Lesser Poland", } labels["Lasovia"] = { Wikipedia = "Lasovia dialect", regional_categories = true, parent = "Lesser Poland", } labels["Eastern Kraków"] = { aliases = {"Eastern Krakow"}, Wikipedia = "Eastern Kraków dialect", regional_categories = true, parent = "Lesser Poland", } labels["Western Kraków"] = { aliases = {"Western Krakow"}, Wikipedia = "Kraków dialect", regional_categories = true, parent = "Lesser Poland", } labels["Lach"] = { Wikipedia = "Sącz Lachs", regional_categories = true, parent = "Lesser Poland", } labels["Podegrodzie"] = { aliases = {"Sącz Lach"}, Wikipedia = "Podegrodzie dialect", regional_categories = true, parent = "Lach", } labels["Limanowa"] = { regional_categories = true, parent = "Lach", } labels["Western Lublin"] = { Wikipedia = "Western Lublin dialect", regional_categories = true, parent = "Lesser Poland", } labels["Eastern Lublin"] = { Wikipedia = "Eastern Lublin dialect", regional_categories = true, parent = "Lesser Poland", } labels["Przemyśl"] = { aliases = {"Przemysl"}, Wikipedia = "Przemyśl dialect", regional_categories = true, parent = "Lesser Poland", } labels["Biecz"] = { Wikipedia = "Biecz dialect", regional_categories = true, parent = "Lesser Poland", } labels["Kraków"] = { aliases = {"Krakow", "Cracow"}, Wikipedia = "Kraków", regional_categories = {true, "Urban"}, parent = "Western Kraków", } labels["Lublin"] = { Wikipedia = true, regional_categories = true, regional_categories = {true, "Urban"}, parent = "Western Lublin", } labels["Łódź"] = { aliases = {"Lodz"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "Łęczyca", } labels["Lviv"] = { aliases = {"Lwów", "Lwow"}, Wikipedia = "Lwów dialect", regional_categories = {true, "Urban"}, parent = "Southern Borderlands", } labels["Goral"] = { aliases = {"Góral"}, Wikipedia = "Goral ethnolect", regional_categories = true, parent = "Lesser Poland", } labels["Podhale"] = { Wikipedia = "Podhale dialect", regional_categories = true, parent = "Goral", } labels["Babia Góra"] = { aliases = {"Babia Gora"}, Wikipedia = "Babia Góra dialect", regional_categories = true, parent = "Goral", } labels["Pieniny"] = { Wikipedia = "Pieniny dialect", regional_categories = true, parent = "Goral", } labels["Łącko"] = { Wikipedia = "Łącko dialect", aliases = {"Lacko"}, regional_categories = true, parent = "Goral", } labels["Piwniczna"] = { Wikipedia = "Piwniczna dialect", regional_categories = true, parent = "Goral", } labels["Kliszczak"] = { Wikipedia = "Kliszczak dialect", regional_categories = true, parent = "Goral", } labels["Żywiec"] = { aliases = {"Zywiec"}, Wikipedia = "Żywiec dialect", regional_categories = true, parent = "Goral", } labels["Orawa"] = { aliases = {"Orava"}, Wikipedia = "Orawa dialect", regional_categories = true, parent = "Goral", } labels["Spisz"] = { Wikipedia = "Spisz dialect", regional_categories = true, parent = "Goral", } labels["Zagórze"] = { Wikipedia = "Zagórze dialect", regional_categories = true, parent = "Goral", } labels["Kysuce"] = { regional_categories = true, parent = "Goral", } labels["Ochotnica"] = { regional_categories = true, parent = "Goral", } labels["Liptov"] = { regional_categories = true, parent = "Goral", } labels["Bukovina"] = { aliases = {"Bucovina", "Bukovinian", "Bukowina"}, Wikipedia = "Bukovinian Polish dialect", regional_categories = true, parent = "Goral", } -- Borderlands dialects labels["Borderlands"] = { aliases = {"Kresy"}, Wikipedia = "Kresy", regional_categories = true, parent = true, } labels["Northern Borderlands"] = { aliases = {"północnokresowy"}, Wikipedia = "Northern Borderlands dialect", regional_categories = true, parent = "Borderlands", } labels["Southern Borderlands"] = { aliases = {"południowokresowy"}, Wikipedia = "Southern Borderlands dialect", regional_categories = true, parent = "Borderlands", } labels["Vilnius"] = { aliases = {"Vilna", "Wilno"}, Wikipedia = true, regional_categories = {true, "Urban", "Northern Borderlands"}, parent = "Northern Borderlands", } -- New mixed dialects labels["New mixed dialects"] = { alias = {"New Mixed Dialects"}, Wikidata = "Q4326522", regional_categories = "New Mixed Dialects", parent = true, } labels["Wrocław"] = { aliases = {"Wroclaw"}, Wikipedia = true, regional_categories = {true, "Urban"}, parent = "New mixed dialects", } labels["Lower Silesia"] = { Wikipedia = true, regional_categories = true, parent = "New mixed dialects", } labels["Malbork"] = { Wikipedia = "Kociewie dialect", regional_categories = true, parent = "Kociewie", } labels["Polish People's Republic"] = { aliases = {"PRL", "PPR"}, Wikipedia = true, topical_categories = true, } -- Historic lables labels["Middle Polish"] = { aliases = {"średniopolski"}, Wikipedia = "en:Middle Polish", display = "ပဝ်လာန်လဒေါဝ်", plain_categories = "ပဝ်လာန်လဒေါဝ်", } labels["pl-pre-1816"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၁၈၁၆)", Wikipedia = "en:History_of_Polish_orthography#19th_century", } labels["pl-pre-1936"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၁၉၃၆)", Wikipedia = "en:History_of_Polish_orthography#1936_reform", } labels["pl-pre-2026"] = { display = "အပြံၚ်အလှာဲခ္ဍံက်လိက်ကၠာနူသၞာံ (၂၀၂၆)", Wikipedia = "en:History_of_Polish_orthography#2026_reform", } -- Grammatical labels labels["reflexive-się"] = { aliases = {"reflexive-sie"}, display = "[[Appendix:Glossary#reflexive|reflexive]] with {{m|pl|się}}", pos_categories = "reflexive verbs", } labels["reflexive-sobie"] = { display = "[[Appendix:Glossary#reflexive|reflexive]] with {{m|pl|sobie}}", pos_categories = "reflexive verbs", } labels["Wieluń"] = { display = "လဳလောန်", } labels["Radomsko"] = { display = "ရာဒေါန်သကဝ်", } return require("Module:labels").finalize_data(labels) thrv7904juhykj89fsp115k11blvwde ထာမ်ပလိက်:inflection-box-bottom 10 117456 396287 395071 2026-06-04T04:59:04Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:inflection-table-bottom]] ဇရေင် [[ထာမ်ပလိက်:inflection-box-bottom]] 395071 wikitext text/x-wiki |} {{#if:{{{notes|}}}|<div class="inflection-table-notes"> {{{notes|}}} </div>}} </div><noinclude>{{documentation}}</noinclude> e198nzkfu9wlfy3e5rljk9mjegp60zq ထာမ်ပလိက်:inflection-box-bottom/documentation 10 294697 396289 395072 2026-06-04T04:59:05Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:inflection-table-bottom/documentation]] ဇရေင် [[ထာမ်ပလိက်:inflection-box-bottom/documentation]] 395072 wikitext text/x-wiki {{documentation subpage}} '''See {{tl|inflection-table-top}}.''' <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်လဗံက်ဂမၠိုၚ်]] [[ကဏ္ဍ:ထာမ်ပလိက်မေတဂမၠိုၚ်]] </includeonly> qwjcrzs749uzmjmalzgdf9u75yq9izq ကာရန်:ပဝ်တူဂြဳ/aw 106 295559 396194 2026-06-03T12:10:47Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|pt|aw|-}} ==ဗွဟ်ရမ္သာၚ်== * '''-au''': ** {{IPA|pt|[ˈaʊ̯]|a=Brazil}} ** {{IPA|pt|[ˈaw]|a=Portugal}} * '''-al''': ''(see also [[Rhymes:ပဝ်တူဂြဳ/al]])'' ** {{IPA|pt|[ˈaʊ̯]|a=Brazil}} ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * {{l|pt|au}} * {{l|pt|cal}} {{a|pt|Brazil}} * {{l|pt|chau}} * {{l|pt|crau}} * {{l|pt|grau}} * {..." 396194 wikitext text/x-wiki {{rhymes nav|pt|aw|-}} ==ဗွဟ်ရမ္သာၚ်== * '''-au''': ** {{IPA|pt|[ˈaʊ̯]|a=Brazil}} ** {{IPA|pt|[ˈaw]|a=Portugal}} * '''-al''': ''(see also [[Rhymes:ပဝ်တူဂြဳ/al]])'' ** {{IPA|pt|[ˈaʊ̯]|a=Brazil}} ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * {{l|pt|au}} * {{l|pt|cal}} {{a|pt|Brazil}} * {{l|pt|chau}} * {{l|pt|crau}} * {{l|pt|grau}} * {{l|pt|jau}} * {{l|pt|mal}} {{a|pt|Brazil}} * {{l|pt|mau}} * {{l|pt|nau}} * {{l|pt|pau}} * {{l|pt|sal}} {{a|pt|Brazil}} * {{l|pt|tal}} {{a|pt|Brazil}} * {{l|pt|tau}} * {{l|pt|tchau}} * {{l|pt|vau}} * {{l|pt|xau}} {{rhyme-bottom}} * '''Suffix''': {{l|pt|-al}} {{a|pt|Brazil}} ===ဝဏ္ဏၜါ=== {{rhyme-top}} * {{l|pt|anal}} {{a|pt|Brazil}} * {{l|pt|aral}} {{a|pt|Brazil}} * {{l|pt|astral}} {{a|pt|Brazil}} * {{l|pt|aval}} {{a|pt|Brazil}} * {{l|pt|Baical}} {{a|pt|Brazil}} * {{l|pt|Baikal}} {{a|pt|Brazil}} * {{l|pt|banal}} {{a|pt|Brazil}} * {{l|pt|bancal}} {{a|pt|Brazil}} * {{l|pt|beiral}} {{a|pt|Brazil}} * {{l|pt|bilau}} * {{l|pt|Bissau}} * {{l|pt|bocal}} {{a|pt|Brazil}} * {{l|pt|boçal}} {{a|pt|Brazil}} * {{l|pt|braçal}} {{a|pt|Brazil}} * {{l|pt|brutal}} {{a|pt|Brazil}} * {{l|pt|bucal}} {{a|pt|Brazil}} * {{l|pt|cabal}} {{a|pt|Brazil}} * {{l|pt|cacau}} * {{l|pt|calau}} * {{l|pt|calhau}} * {{l|pt|camal}} {{a|pt|Brazil}} * {{l|pt|campal}} {{a|pt|Brazil}} * {{l|pt|canal}} {{a|pt|Brazil}} * {{l|pt|carnal}} {{a|pt|Brazil}} * {{l|pt|casal}} {{a|pt|Brazil}} * {{l|pt|caudal}} {{a|pt|Brazil}} * {{l|pt|causal}} {{a|pt|Brazil}} * {{l|pt|central}} {{a|pt|Brazil}} * {{l|pt|cerval}} {{a|pt|Brazil}} * {{l|pt|chacal}} {{a|pt|Brazil}} * {{l|pt|coral}} {{a|pt|Brazil}} * {{l|pt|cristal}} {{a|pt|Brazil}} * {{l|pt|curral}} {{a|pt|Brazil}} * {{l|pt|dedal}} {{a|pt|Brazil}} * {{l|pt|degrau}} * {{l|pt|dental}} {{a|pt|Brazil}} * {{l|pt|dorsal}} {{a|pt|Brazil}} * {{l|pt|dual}} {{a|pt|Brazil}} * {{l|pt|ducal}} {{a|pt|Brazil}} * {{l|pt|fatal}} {{a|pt|Brazil}} * {{l|pt|fecal}} {{a|pt|Brazil}} * {{l|pt|fetal}} {{a|pt|Brazil}} * {{l|pt|feudal}} {{a|pt|Brazil}} * {{l|pt|final}} {{a|pt|Brazil}} * {{l|pt|fiscal}} {{a|pt|Brazil}} * {{l|pt|floral}} {{a|pt|Brazil}} * {{l|pt|focal}} {{a|pt|Brazil}} * {{l|pt|fogal}} {{a|pt|Brazil}} * {{l|pt|foral}} {{a|pt|Brazil}} * {{l|pt|formal}} {{a|pt|Brazil}} * {{l|pt|frugal}} {{a|pt|Brazil}} * {{l|pt|funchal}} {{a|pt|Brazil}} * {{l|pt|Funchal}} {{a|pt|Brazil}} * {{l|pt|futsal}} {{a|pt|Brazil}} * {{l|pt|gatal}} {{a|pt|Brazil}} * {{l|pt|geral}} {{a|pt|Brazil}} * {{l|pt|global}} {{a|pt|Brazil}} * {{l|pt|glotal}} {{a|pt|Brazil}} * {{l|pt|grupal}} {{a|pt|Brazil}} * {{l|pt|jirau}} * {{l|pt|jogral}} {{a|pt|Brazil}} * {{l|pt|jornal}} {{a|pt|Brazil}} * {{l|pt|lacrau}} * {{l|pt|legal}} {{a|pt|Brazil}} * {{l|pt|letal}} {{a|pt|Brazil}} * {{l|pt|local}} {{a|pt|Brazil}} * {{l|pt|Macau}} * {{l|pt|mancal}} {{a|pt|Brazil}} * {{l|pt|mensal}} {{a|pt|Brazil}} * {{l|pt|mental}} {{a|pt|Brazil}} * {{l|pt|metal}} {{a|pt|Brazil}} * {{l|pt|miau}} * {{l|pt|mingau}} * {{l|pt|modal}} {{a|pt|Brazil}} * {{l|pt|moral}} {{a|pt|Brazil}} * {{l|pt|mortal}} {{a|pt|Brazil}} * {{l|pt|mural}} {{a|pt|Brazil}} * {{l|pt|narval}} {{a|pt|Brazil}} * {{l|pt|natal}} {{a|pt|Brazil}} * {{l|pt|Natal}} {{a|pt|Brazil}} * {{l|pt|Nepal}} {{a|pt|Brazil}} * {{l|pt|neural}} {{a|pt|Brazil}} * {{l|pt|normal}} {{a|pt|Brazil}} * {{l|pt|oral}} {{a|pt|Brazil}} * {{l|pt|oval}} {{a|pt|Brazil}} * {{l|pt|Palau}} * {{l|pt|pardal}} {{a|pt|Brazil}} * {{l|pt|pardau}} * {{l|pt|pedal}} {{a|pt|Brazil}} * {{l|pt|penal}} {{a|pt|Brazil}} * {{l|pt|pilau}} * {{l|pt|pinhal}} {{a|pt|Brazil}} * {{l|pt|podal}} {{a|pt|Brazil}} * {{l|pt|pombal}} {{a|pt|Brazil}} * {{l|pt|Pombal}} {{a|pt|Brazil}} * {{l|pt|pontal}} {{a|pt|Brazil}} * {{l|pt|portal}} {{a|pt|Brazil}} * {{l|pt|postal}} {{a|pt|Brazil}} * {{l|pt|punhal}} {{a|pt|Brazil}} * {{l|pt|quintal}} {{a|pt|Brazil}} * {{l|pt|quiral}} {{a|pt|Brazil}} * {{l|pt|ramal}} {{a|pt|Brazil}} * {{l|pt|real}} {{a|pt|Brazil}} * {{l|pt|renal}} {{a|pt|Brazil}} * {{l|pt|retal}} {{a|pt|Brazil}} * {{l|pt|sarau}} * {{l|pt|Seixal}} {{a|pt|Brazil}} * {{l|pt|serval}} {{a|pt|Brazil}} * {{l|pt|sinal}} {{a|pt|Brazil}} * {{l|pt|sobral}} {{a|pt|Brazil}} * {{l|pt|Sobral}} {{a|pt|Brazil}} * {{l|pt|termal}} {{a|pt|Brazil}} * {{l|pt|tonal}} {{a|pt|Brazil}} * {{l|pt|total}} {{a|pt|Brazil}} * {{l|pt|tribal}} {{a|pt|Brazil}} * {{l|pt|uau}} * {{l|pt|venal}} {{a|pt|Brazil}} * {{l|pt|ventral}} {{a|pt|Brazil}} * {{l|pt|verbal}} {{a|pt|Brazil}} * {{l|pt|Vidal}} {{a|pt|Brazil}} * {{l|pt|vidral}} {{a|pt|Brazil}} * {{l|pt|vital}} {{a|pt|Brazil}} * {{l|pt|vitral}} {{a|pt|Brazil}} * {{l|pt|vocal}} {{a|pt|Brazil}} * {{l|pt|vogal}} {{a|pt|Brazil}} * {{l|pt|zagal}} {{a|pt|Brazil}} * {{l|pt|zonal}} {{a|pt|Brazil}} {{rhyme-bottom}} ===ဝဏ္ဏပိ=== {{rhyme-top}} * {{l|pt|abissal}} {{a|pt|Brazil}} * {{l|pt|afixal}} * {{l|pt|amoral}} {{a|pt|Brazil}} * {{l|pt|animal}} {{a|pt|Brazil}} * {{l|pt|anormal}} {{a|pt|Brazil}} * {{l|pt|atonal}} * {{l|pt|avental}} {{a|pt|Brazil}} * {{l|pt|bacalhau}} * {{l|pt|bacanal}} {{a|pt|Brazil}} * {{l|pt|berimbau}} * {{l|pt|capital}} {{a|pt|Brazil}} * {{l|pt|carnaval}} {{a|pt|Brazil}} * {{l|pt|casual}} {{a|pt|Brazil}} * {{l|pt|colorau}} * {{l|pt|cordial}} {{a|pt|Brazil}} * {{l|pt|crucial}} {{a|pt|Brazil}} * {{l|pt|cultural}} {{a|pt|Brazil}} * {{l|pt|digital}} {{a|pt|Brazil}} * {{l|pt|distrital}} {{a|pt|Brazil}} * {{l|pt|edital}} {{a|pt|Brazil}} * {{l|pt|estatal}} {{a|pt|Brazil}} * {{l|pt|factual}} {{a|pt|Brazil}} * {{l|pt|fatual}} {{a|pt|Brazil}} * {{l|pt|florestal}} {{a|pt|Brazil}} * {{l|pt|fraternal}} {{a|pt|Brazil}} * {{l|pt|general}} {{a|pt|Brazil}} * {{l|pt|genital}} {{a|pt|Brazil}} * {{l|pt|hospital}} {{a|pt|Brazil}} * {{l|pt|imoral}} {{a|pt|Brazil}} * {{l|pt|imortal}} {{a|pt|Brazil}} * {{l|pt|integral}} {{a|pt|Brazil}} * {{l|pt|jovial}} {{a|pt|Brazil}} * {{l|pt|laboral}} {{a|pt|Brazil}} * {{l|pt|lateral}} {{a|pt|Brazil}} * {{l|pt|lexical}} {{a|pt|Brazil}} * {{l|pt|marital}} {{a|pt|Brazil}} * {{l|pt|Mindanau}} * {{l|pt|Nicolau}} * {{l|pt|orbital}} {{a|pt|Brazil}} * {{l|pt|parental}} {{a|pt|Brazil}} * {{l|pt|pedestal}} {{a|pt|Brazil}} * {{l|pt|pica-pau}} * {{l|pt|pirilau}} * {{l|pt|Portugal}} {{a|pt|Brazil}} * {{l|pt|quengaral}} * {{l|pt|radial}} {{a|pt|Brazil}} * {{l|pt|radical}} {{a|pt|Brazil}} * {{l|pt|sazonal}} {{a|pt|Brazil}} * {{l|pt|sexual}} {{a|pt|Brazil}} * {{l|pt|social}} {{a|pt|Brazil}} * {{l|pt|subtotal}} {{a|pt|Brazil}} * {{l|pt|surreal}} {{a|pt|Brazil}} * {{l|pt|temporal}} {{a|pt|Brazil}} * {{l|pt|trivial}} {{a|pt|Brazil}} * {{l|pt|tropical}} {{a|pt|Brazil}} * {{l|pt|urutau}} * {{l|pt|varapau}} * {{l|pt|vegetal}} {{a|pt|Brazil}} * {{l|pt|Venceslau}} {{rhyme-bottom}} ===ဝဏ္ဏပန်=== {{rhyme-top}} * {{l|pt|acidental}} {{a|pt|Brazil}} * {{l|pt|ambiental}} {{a|pt|Brazil}} * {{l|pt|angelical}} {{a|pt|Brazil}} * {{l|pt|artesanal}} {{a|pt|Brazil}} * {{l|pt|assexual}} {{a|pt|Brazil}} * {{l|pt|atemporal}} {{a|pt|Brazil}} * {{l|pt|bilateral}} {{a|pt|Brazil}} * {{l|pt|coloquial}} {{a|pt|Brazil}} * {{l|pt|conceitual}} {{a|pt|Brazil}} * {{l|pt|conceptual}} {{a|pt|Brazil}} * {{l|pt|conjuntural}} {{a|pt|Brazil}} * {{l|pt|consensual}} {{a|pt|Brazil}} * {{l|pt|continental}} {{a|pt|Brazil}} * {{l|pt|essencial}} {{a|pt|Brazil}} * {{l|pt|estadual}} {{a|pt|Brazil}} * {{l|pt|estamental}} {{a|pt|Brazil}} * {{l|pt|funcional}} {{a|pt|Brazil}} * {{l|pt|horizontal}} {{a|pt|Brazil}} * {{l|pt|imparcial}} {{a|pt|Brazil}} * {{l|pt|incidental}} {{a|pt|Brazil}} * {{l|pt|incremental}} {{a|pt|Brazil}} * {{l|pt|inicial}} {{a|pt|Brazil}} * {{l|pt|instrumental}} {{a|pt|Brazil}} * {{l|pt|monumental}} {{a|pt|Brazil}} * {{l|pt|nacional}} {{a|pt|Brazil}} * {{l|pt|ocidental}} {{a|pt|Brazil}} * {{l|pt|oriental}} {{a|pt|Brazil}} * {{l|pt|ornamental}} {{a|pt|Brazil}} * {{l|pt|ortogonal}} {{a|pt|Brazil}} * {{l|pt|pansexual}} {{a|pt|Brazil}} * {{l|pt|paradoxal}} {{a|pt|Brazil}} * {{l|pt|pentecostal}} {{a|pt|Brazil}} * {{l|pt|potencial}} {{a|pt|Brazil}} * {{l|pt|primordial}} {{a|pt|Brazil}} * {{l|pt|sentimental}} {{a|pt|Brazil}} * {{l|pt|transcendental}} {{a|pt|Brazil}} * {{l|pt|transexual}} {{a|pt|Brazil}} {{rhyme-bottom}} ===ဝဏ္ဏမသုန်=== {{rhyme-top}} * {{l|pt|antissocial}} {{a|pt|Brazil}} * {{l|pt|atitudinal}} {{a|pt|Brazil}} * {{l|pt|bidialetal}} * {{l|pt|comportamental}} {{a|pt|Brazil}} * {{l|pt|condicional}} {{a|pt|Brazil}} * {{l|pt|departamental}} {{a|pt|Brazil}} * {{l|pt|disfuncional}} {{a|pt|Brazil}} * {{l|pt|excecional}} {{a|pt|Brazil}} * {{l|pt|excepcional}} {{a|pt|Brazil}} * {{l|pt|experimental}} {{a|pt|Brazil}} * {{l|pt|intelectual}} {{a|pt|Brazil}} * {{l|pt|interpessoal}} {{a|pt|Brazil}} * {{l|pt|irracional}} {{a|pt|Brazil}} * {{l|pt|metrossexual}} {{a|pt|Brazil}} * {{l|pt|papanicolau}} * {{l|pt|paraestatal}} {{a|pt|Brazil}} * {{l|pt|procedimental}} {{a|pt|Brazil}} * {{l|pt|sensacional}} * {{l|pt|superficial}} {{a|pt|Brazil}} * {{l|pt|temperamental}} {{a|pt|Brazil}} * {{l|pt|transnacional}} {{a|pt|Brazil}} * {{l|pt|unilateral}} {{a|pt|Brazil}} {{rhyme-bottom}} ===ဝဏ္ဏတရဴ=== {{rhyme-top}} * {{l|pt|bidimensional}} {{a|pt|Brazil}} * {{l|pt|contingencial}} {{a|pt|Brazil}} * {{l|pt|incondicional}} {{a|pt|Brazil}} * {{l|pt|institucional}} {{a|pt|Brazil}} * {{l|pt|internacional}} {{a|pt|Brazil}} * {{l|pt|tridimensional}} {{a|pt|Brazil}} {{rhyme-bottom}} ===ဝဏ္ဏထပှ်=== {{rhyme-top}} * {{l|pt|multidimensional}} {{a|pt|Brazil}} * {{l|pt|pluridimensional}} {{a|pt|Brazil}} * {{l|pt|quadridimensional}} {{a|pt|Brazil}} * {{l|pt|tetradimensional}} {{a|pt|Brazil}} * {{l|pt|unidimensional}} {{a|pt|Brazil}} {{rhyme-bottom}} tqrz9o0mi2cvs8lnou8wf1art0srtv2 ကာရန်:ပဝ်တူဂြဳ/aw- 106 295560 396195 2026-06-03T12:19:24Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|pt|aw}} ==Notes== In {{w|Brazilian Portuguese}}, ''al'' and ''aw'' are homophones, so some rhymes might only be valid in Brazilian Portuguese and not in {{w|European Portuguese}}. See also [[Rhymes:ပဝ်တူဂြဳ/al-]]. ===Oxytones=== * {{rhymes row|pt|aw|mau, degrau, sal {{a|pt|Brazil}}, geral {{a|pt|Brazil}}}} ===Paroxytones=== ===={{IPAchar|/d/}}==== * {{rhymes row|pt|awdɐ|cauda, fralda..." 396195 wikitext text/x-wiki {{rhymes nav|pt|aw}} ==Notes== In {{w|Brazilian Portuguese}}, ''al'' and ''aw'' are homophones, so some rhymes might only be valid in Brazilian Portuguese and not in {{w|European Portuguese}}. See also [[Rhymes:ပဝ်တူဂြဳ/al-]]. ===Oxytones=== * {{rhymes row|pt|aw|mau, degrau, sal {{a|pt|Brazil}}, geral {{a|pt|Brazil}}}} ===Paroxytones=== ===={{IPAchar|/d/}}==== * {{rhymes row|pt|awdɐ|cauda, fralda {{a|pt|Brazil}}, esmeralda {{a|pt|Brazil}}}} * {{rhymes row|pt|awdɨ|fraude, aplaude, defraude}} {{a|pt|Portugal}} * {{rhymes row|pt|awdʒi|balde, fraude, escalde}} {{a|pt|Brazil}} * {{rhymes row|pt|awdu|laudo, aplaudo, caldo {{a|pt|Brazil}}, Arnaldo {{a|pt|Brazil}}}} ===={{IPAchar|/f/}}==== * {{rhymes row|pt|awfɐ|alfa {{a|pt|Brazil}}, escalfa {{a|pt|Brazil}}}} * {{rhymes row|pt|awfi|escalfe}} {{a|pt|Brazil}} * {{rhymes row|pt|awfu|escalfo}} {{a|pt|Brazil}} ===={{IPAchar|/ɡ/}}==== * {{rhymes row|pt|awɡɐ|auga, alga {{a|pt|Brazil}}, cavalga {{a|pt|Brazil}}}} * {{rhymes row|pt|awɡi|galgue, salgue, cavalgue}} {{a|pt|Brazil}} * {{rhymes row|pt|awɡu|augo, algo {{a|pt|Brazil}}, galgo {{a|pt|Brazil}}, fidalgo {{a|pt|Brazil}}}} ===={{IPAchar|/ʒ/}}==== * {{rhymes row|pt|awʒi|auge}} ===={{IPAchar|/k/}}==== * {{rhymes row|pt|awkɐ|glauca, desfalca {{a|pt|Brazil}}, recalca {{a|pt|Brazil}}}} * {{rhymes row|pt|awki|calque, desfalque, recalque}} {{a|pt|Brazil}} * {{rhymes row|pt|awku|glauco, palco {{a|pt|Brazil}}, recalco {{a|pt|Brazil}}}} ===={{IPAchar|/l/}}==== * {{rhymes row|pt|awlɐ|aula, jaula, Paula}} * {{rhymes row|pt|awli|caule}} * {{rhymes row|pt|awlu|Paulo}} ===={{IPAchar|/m/}}==== * {{rhymes row|pt|awmɐ|alma {{a|pt|Brazil}}, trauma, palma {{a|pt|Brazil}}}} * {{rhymes row|pt|awmi|acalme, espalme}} {{a|pt|Brazil}} * {{rhymes row|pt|awmu|calmo {{a|pt|Brazil}}, salmo {{a|pt|Brazil}}, acalmo {{a|pt|Brazil}}}} ===={{IPAchar|/n/}}==== * {{rhymes row|pt|awnɐ|sauna, fauna, microfauna}} * {{rhymes row|pt|awnu|fauno}} ===={{IPAchar|/ɾ/}}==== * {{rhymes row|pt|awɾɐ|aura, maura, restaura}} * {{rhymes row|pt|awɾu|mauro, restauro, dinossauro}} ===={{IPAchar|/ʁ/}}==== * {{rhymes row|pt|awʁɐ|palra}} {{a|pt|Brazil}} * {{rhymes row|pt|awʁɨ|palre}} {{a|pt|Brazil}} * {{rhymes row|pt|awʁu|palro}} {{a|pt|Brazil}} ===={{IPAchar|/s/}}==== * {{rhymes row|pt|awsɐ|calça {{a|pt|Brazil}}, falsa {{a|pt|Brazil}}, descalça {{a|pt|Brazil}}}} * {{rhymes row|pt|awsɨ|fauce}} {{a|pt|Portugal}} * {{rhymes row|pt|awsi|alce, calce, descalce}} {{a|pt|Brazil}} * {{rhymes row|pt|awsu|falso {{a|pt|Brazil}}, calço {{a|pt|Brazil}}, realço {{a|pt|Brazil}}}} ===={{IPAchar|/t/}}==== * {{rhymes row|pt|awtɐ|alta {{a|pt|Brazil}}, nauta, astronauta, sobressalta {{a|pt|Brazil}}}} * {{rhymes row|pt|awtɨ}}, {{rhymes row|pt|awt͡ʃi}}, {{rhymes row|pt|awti|blecaute, falte {{a|pt|Brazil}}, esmalte {{a|pt|Brazil}}}} * {{rhymes row|pt|awtu|auto, salto {{a|pt|Brazil}}, incauto}} ===={{IPAchar|/v/}}==== * {{rhymes row|pt|awvɐ|alva {{a|pt|Brazil}}, salva {{a|pt|Brazil}}, ressalva {{a|pt|Brazil}}}} * {{rhymes row|pt|awvi|salve {{a|pt|Brazil}}, bivalve {{a|pt|Brazil}}, ressalve {{a|pt|Brazil}}}} * {{rhymes row|pt|awvu|calvo {{a|pt|Brazil}}, ressalvo {{a|pt|Brazil}}, público-alvo {{a|pt|Brazil}}}} ===={{IPAchar|/z/}}==== * {{rhymes row|pt|awzɐ|causa, pausa, menopausa}} * {{rhymes row|pt|awzi|cause, pause}} * {{rhymes row|pt|awzu|causo, pauso, aplauso}} sgnbsnmv2g6yybu1g9emwwzpsv4f5u7 ကဏ္ဍ:ကာရန်ပဝ်တူဂြဳဂမၠိုၚ်/aw- 14 295561 396196 2026-06-03T12:29:27Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ကာရန်ပဝ်တူဂြဳဂမၠိုၚ်|aw-]]" 396196 wikitext text/x-wiki [[ကဏ္ဍ:ကာရန်ပဝ်တူဂြဳဂမၠိုၚ်|aw-]] 7rt8vwajw7uc0cqqxymhkpzhwyhsu50 ကဏ္ဍ:ကာရန်:အိန်ဒဝ်နဳသဳယျာ/al 14 295562 396199 2026-06-03T12:50:29Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာအိန်ဒဝ်နဳသဳယျာ|အိန်ဒဝ်နဳ..." 396199 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာအိန်ဒဝ်နဳသဳယျာ|အိန်ဒဝ်နဳသဳယျာ]] » [[:ကဏ္ဍ:ကာရန်:အိန်ဒဝ်နဳသဳယျာ|ကာရန်ဂမၠိုၚ်]] » -al :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာအိန်ဒဝ်နဳသဳယျာ|အိန်ဒဝ်နဳသဳယျာ]]မနွံကာရန် [[ကာရန်:အိန်ဒဝ်နဳသဳယျာ/al|-al]] ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:အိန်ဒဝ်နဳသဳယျာ|al]] sv161ch7xwhljxek689nmh2fl0kjri9 ကာရန်:အိန်ဒဝ်နဳသဳယျာ/al 106 295563 396200 2026-06-03T13:00:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|id|a|l}} ==ဗွဟ်ရမ္သာၚ်== {{id-IPA|al}} ==မအရေဝ်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * {{l|id|hal}} * {{l|id|mal}} * {{l|id|pal}} * {{l|id|syal}} {{rhyme-bottom}} ===ဝဏ္ဏၜါ=== {{rhyme-top}} * {{l|id|bebal}} * {{l|id|bekal}} * {{l|id|cekal}} * {{l|id|empal}} * {{l|id|jengkal}} * {{l|id|kebal}} * {{l|id|kekal}} * {{l|id|kenal}} *..." 396200 wikitext text/x-wiki {{rhymes nav|id|a|l}} ==ဗွဟ်ရမ္သာၚ်== {{id-IPA|al}} ==မအရေဝ်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * {{l|id|hal}} * {{l|id|mal}} * {{l|id|pal}} * {{l|id|syal}} {{rhyme-bottom}} ===ဝဏ္ဏၜါ=== {{rhyme-top}} * {{l|id|bebal}} * {{l|id|bekal}} * {{l|id|cekal}} * {{l|id|empal}} * {{l|id|jengkal}} * {{l|id|kebal}} * {{l|id|kekal}} * {{l|id|kenal}} * {{l|id|kental}} * {{l|id|kenyal}} * {{l|id|kesal}} * {{l|id|mental}} * {{l|id|pedal}} * {{l|id|pejal}} * {{l|id|perbal}} * {{l|id|tebal}} * {{l|id|terpal}} {{rhyme-bottom}} ===ဝဏ္ဏပိ=== {{rhyme-top}} * {{l|id|berbekal}} * {{l|id|bermental}} * {{l|id|berpedal}} * {{l|id|dicekal}} * {{l|id|dijengkal}} * {{l|id|dikenal}} * {{l|id|dipedal}} * {{l|id|diperbal}} * {{l|id|empedal}} * {{l|id|federal}} * {{l|id|memedal}} * {{l|id|memenggal}} * {{l|id|mencekal}} * {{l|id|menebal}} * {{l|id|mengebal}} * {{l|id|mengenal}} * {{l|id|mengental}} * {{l|id|mengenyal}} * {{l|id|menjengkal}} * {{l|id|menyesal}} * {{l|id|pembekal}} * {{l|id|penebal}} * {{l|id|pertebal}} * {{l|id|pengental}} * {{l|id|sejengkal}} * {{l|id|sekental}} * {{l|id|sekenyal}} * {{l|id|sekesal}} * {{l|id|setebal}} * {{l|id|terkenal}} * {{l|id|terkental}} * {{l|id|terkenyal}} * {{l|id|terkesal}} * {{l|id|tertebal}} {{rhyme-bottom}} fj1sc2t5oy9zo4z39cy10xgsbqyzmyg materiał 0 295564 396201 2026-06-03T13:10:59Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|material|Material|materiál|materiał}} ==ပဝ်လာန်== {{wp|pl:}} ===ပွံၚ်နဲတၞဟ်=== * {{alt|pl|materyjał||Middle Polish|Sieradz|Wieluń|Radomsko}} * {{alt|pl|materjał||pl-pre-1936}} ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr|a=Pl-#.ogg}} ===နာမ်=== {{pl-noun|m-in|adj=materiałowy|dim=materialik|abbr=mat.}} # ကပေါတ်ကညောတ်။ # ကယာ..." 396201 wikitext text/x-wiki {{also|material|Material|materiál|materiał}} ==ပဝ်လာန်== {{wp|pl:}} ===ပွံၚ်နဲတၞဟ်=== * {{alt|pl|materyjał||Middle Polish|Sieradz|Wieluń|Radomsko}} * {{alt|pl|materjał||pl-pre-1936}} ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr|a=Pl-#.ogg}} ===နာမ်=== {{pl-noun|m-in|adj=materiałowy|dim=materialik|abbr=mat.}} # ကပေါတ်ကညောတ်။ # ကယာဗာ။ #: {{syn|pl|tworzywo}} # ပရေၚ်မဇၞော်ကေၚ်ကာ။ #: {{syn|pl|materia}} # ပရေၚ်မၞုံကဵုပၟိက်။ #: {{syn|pl|kandydat}} ====လဟုတ်စှ်ေ==== {{pl-decl-noun-m-in}} ===မဒုၚ်လွဳစ=== * {{desc|csb|materiôł|bor=1}} 6kd2jozgnc877f5u4atly48cqi4hi7n ထာမ်ပလိက်:pl-decl-noun-m-in 10 295565 396202 2026-06-03T13:11:45Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|m-in}}<noinclude>{{documentation}}</noinclude>" 396202 wikitext text/x-wiki {{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|m-in}}<noinclude>{{documentation}}</noinclude> dex2z0277mk2cy994m0rfaso5kzxwdr မဝ်ဂျူ:pl-noun 828 295566 396203 2026-06-03T13:21:22Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local export = {} local m_links = require('Module:links') local m_adj = require('Module:pl-adj') local m_g = require('Module:gender and number') local lang = require("Module:languages").getByCode("pl") -- local consonants = "[bcćdfghjklłmnńpqrsśtvwxzżź]"; -- case information local cases = { { key = "nom"; en = "မဒုၚ်ယၟု"; pl = "mianownik (kto? co?)" }, { key = "gen"; en = "ဗဳဇဂကူ..." 396203 Scribunto text/plain local export = {} local m_links = require('Module:links') local m_adj = require('Module:pl-adj') local m_g = require('Module:gender and number') local lang = require("Module:languages").getByCode("pl") -- local consonants = "[bcćdfghjklłmnńpqrsśtvwxzżź]"; -- case information local cases = { { key = "nom"; en = "မဒုၚ်ယၟု"; pl = "mianownik (kto? co?)" }, { key = "gen"; en = "ဗဳဇဂကူ"; pl = "dopełniacz (kogo? czego?)" }, { key = "dat"; en = "ပြကမ္မကာရက"; pl = "celownik (komu? czemu?)" }, { key = "acc"; en = "ကမ္မကာရက"; pl = "biernik (kogo? co?)" }, { key = "ins"; en = "တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်"; pl = "narzędnik (kim? czym?)" }, { key = "loc"; en = "ခၞံဗဒှ်ဌာန်မတန်တဴ"; pl = "miejscownik (o kim? o czym?)" }, { key = "voc"; en = "ပရေၚ်ဂယိုၚ်လမျီု"; pl = "wołacz (o!)" }, } -- columns for normal nouns local noun_cols = { { key = "s"; title = "ကိုန်ဨကဝုစ်" }, { key = "p"; title = "ကိုန်ဗဟုဝစ်" }, } -- columns for Old Polish nouns local noun_dual_cols = { { key = "s"; title = "ကိုန်ဨကဝုစ်" }, { key = "d"; title = "ၜါလ္ပာ်" }, { key = "p"; title = "ကိုန်ဗဟုဝစ်" }, } -- columns for pronouns local pronoun_cols = { { key = "sm"; title = m_g.format_list({"m"}, lang) }, { key = "sf"; title = m_g.format_list({"f"}, lang) }, { key = "sn"; title = m_g.format_list({"n"}, lang) }, { key = "pm"; title = m_g.format_list({"vr-p"}, lang) }, { key = "po"; title = m_g.format_list({"nv-p"}, lang) }, } local altsep = "/" function empty_item(text) return (not text) or text == "" or text == "-" or text == "–" or text == "—" end -- add link markers, with links separated by any of splitchars -- exported for use in testcases -- normally the separator is altsep function export.make_links(text, splitchars, title) if not title then title = mw.loadData("Module:headword/data").pagename end if empty_item(text) then return "—" elseif not splitchars or splitchars == "" then return ("[[%s#ပဝ်လာန်|%s]]"):format(text, text) else items = {} for word in mw.ustring.gmatch(text, "[^" .. splitchars .. "]+") do add_archaic = "" add_deprecative = "" if word:sub(-string.len(" (archaic)")) == " (archaic)" then word = (mw.text.split(word, "% %(archaic%)"))[1] add_archaic = " (archaic)" end if word:sub(-string.len(" (deprecative)")) == " (deprecative)" then word = (mw.text.split(word, "% %(deprecative%)"))[1] add_deprecative = " (deprecative)" end if word == title then table.insert(items, ("[[%s]]"):format(word) .. add_archaic .. add_deprecative) else table.insert(items, ("[[%s#ပဝ်လာန်|%s]]"):format(word, word) .. add_archaic .. add_deprecative) end end if #items > 1 then require("Module:debug").track("pl-noun/splitchars") end return table.concat(items, "/") end end local function linkify_info(declinfo, splitchars, nolinks) if nolinks then require("Module:debug").track("pl-noun/nolinks") end local linked = {} local title = mw.loadData("Module:headword/data").pagename for k, v in pairs(declinfo) do if v == title then linked[k] = "[[" .. v .. "]]" elseif nolinks then linked[k] = v else linked[k] = export.make_links(v, splitchars, title) end end return linked end local function nowiki_info(declinfo) require("Module:debug").track("pl-noun/nowiki") local nowikied = {} for k, v in pairs(declinfo) do nowikied[k] = mw.text.nowiki(v) end return nowikied end local function override_col_titles(heads, cols) if not heads then return cols or {} end local new_cols = {} local index = 1 for word in mw.ustring.gmatch(heads, "[^,]+") do if cols[index] then table.insert(new_cols, { key = cols[index].key; title = word } ) else table.insert(new_cols, { key = tostring(index); title = word } ) end index = index + 1 end for ci, col in ipairs(cols) do if ci >= index then table.insert(new_cols, cols[index]) end end return new_cols end local function normalize_tantum(pargs) -- support "num" as fallback for "tantum" to match Latin templates local tantum = pargs.tantum or pargs.num if not tantum then return nil end if tantum == "sg" then tantum = "s" elseif tantum == "pl" then tantum = "p" end return tantum end local function guess_width(declinfo, cols) local maxl = 0 for k, v in pairs(declinfo) do local l = mw.ustring.len(mw.text.trim(v)) if maxl < l then maxl = l end end local width = math.floor(maxl * 0.78) -- number obtained by anecdotal evidence width = (width < 10) and 10 or width width = 9 + (width * #cols) return width end -- generate the HTML code of an inflection table -- each entry in heads must have "key" and "title" local function make_table(declinfo, cols, preproc, width, title, tantum, nolinks) local result = {} if not cols or not cols[1] then error("make_table: invalid cols parameter") end local lemma_key = cases[1].key .. cols[1].key local lemma = m_links.remove_links(declinfo[lemma_key]) title = title or ('မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <span class="Latn mention" lang="pl" xml:lang="pl">%s</span>'):format(lemma) local emwidth = width or guess_width(declinfo, cols) if preproc == "nowiki" then declinfo = nowiki_info(declinfo) elseif preproc == "linkify" then declinfo = linkify_info(declinfo, altsep, nolinks) end if cols and (#cols > 0) then table.insert(result, '|- class="rowgroup"\n! style="background:var(--wikt-palette-lightblue, #d9ebff); width: 8em;" |\n') for i, col in ipairs(cols) do table.insert(result, ('! style="background:var(--wikt-palette-lightblue, #d9ebff);" scope="col" | %s\n'):format(col.title)) end end local maxl = 0 for i, case in ipairs(cases) do table.insert(result, ('|-\n! title="%s" style="background:var(--wikt-palette-lighterblue, #ebf4ff);" scope="row" | %s\n'):format(case.pl, case.en)) for _, col in ipairs(cols) do local declkey = case.key .. col.key local item = mw.text.trim(declinfo[declkey]) if empty_item(item) then table.insert(result, '| —\n') else local link = m_links.full_link({lang = lang, term = item, accel = {form = ("%s|%s"):format(case.key, col.key)}}) table.insert(result, ('| %s\n'):format(link)) end end end local outtext = ([=[<div class="NavFrame" data-toggle-category="declension" style="display: block; max-width: %uem;"> <div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff)" >%s</div> <div class="NavContent"> {| style="text-align:center; width: 100%%; margin: 0;" class="inflection-table inflection" ]=]):format(emwidth, title) .. table.concat(result, "") .. "|}</div></div>" if tantum == "s" then outtext = outtext .. "[[Category:Polish singularia tantum]]" elseif tantum == "p" then outtext = outtext .. "[[Category:Polish pluralia tantum]]" end return outtext end local function get_mode() local frame = mw.getCurrentFrame() if mw.isSubsting() then return 'subst' elseif frame:getParent():getTitle() == mw.title.getCurrentTitle().fullText then -- The invoking template is being called on the template page itself return 'demo' else return 'xclude' end end local function make_table_from_pargs(pargs, cols, tantum) local width = pargs.width and tonumber(pargs.width) local declinfo = {} if get_mode() == 'demo' then if not cols then cols = { { key = "1"; title = "column 1" }, { key = "2"; title = "column 2" }, { key = "3"; title = "column 3" }, } end for i = 1, 7 do for j, col in ipairs(cols) do local case_key = cases[i].key .. col.key local argn = (i-1) * #cols + j declinfo[case_key] = '{{{' .. case_key .. '| {{{' .. argn .. '}}} }}}' end end return make_table(declinfo, cols, "nowiki", width, nil, nil, nil) else cols = override_col_titles(pargs.heads, cols or {}) for i = 1, 7 do for j, col in ipairs(cols) do local case_key = cases[i].key .. col.key local argn = ((i-1) * #cols) + j declinfo[case_key] = m_links.remove_links(mw.text.trim(pargs[case_key] or pargs[argn] or "-")) end end return make_table(declinfo, cols, "linkify", pargs.width, pargs.title, normalize_tantum(pargs), pargs.nolinks) end end -- Generate declension table for a singulare tantum with all forms passed explicitly as parameters function export.template_decl_noun_sg(frame) local pargs = frame:getParent().args local cols = { noun_cols[1] } return make_table_from_pargs(pargs, cols, "s") end -- Generate declension table for a plurale tantum with all forms passed explicitly as parameters function export.template_decl_noun_pl(frame) local pargs = frame:getParent().args local cols = { noun_cols[2] } return make_table_from_pargs(pargs, cols, "p") end -- Generate declension table for a regular noun with all forms passed explicitly as parameters function export.template_decl_noun(frame) local pargs = frame:getParent().args return make_table_from_pargs(pargs, noun_cols, nil) end function export.template_decl_pronoun(frame) local pargs = frame:getParent().args return make_table_from_pargs(pargs, pronoun_cols, nil) end -- this probably belongs in a module for Old Polish (zlw-opl). -- which reminds me: someone should write [[WT:AZLW-OPL]]. -- Generate declension table for a noun with dual number with all forms passed explicitly as parameters function export.template_decl_noun_dual(frame) local pargs = frame:getParent().args return make_table_from_pargs(pargs, noun_dual_cols, nil) end function export.template_decl_generic(frame) local pargs = frame:getParent().args local heads = pargs.heads if not heads then if get_mode() == "demo" then heads = "column 1,column 2" else error("No column headings defined!") end end local cols = override_col_titles(heads, {}) return make_table_from_pargs(pargs, cols, nil) end -- ----------------------------------------------------------------------------- -- ----------------------------------------------------------------------------- -- ------------- Semi-automatic generation of inflected forms ------------------ -- ----------------------------------------------------------------------------- -- ----------------------------------------------------------------------------- local function nonempty(str) if not str or str == "" then return nil else return str end end -- Generate a table contains true for each space-separated word in str local function make_lookup_table(str) local ret = {} for i in mw.ustring.gmatch(str, "%a+") do ret[i] = true end return ret end -- table that converts nominative soft endings to their genitive form -- required for proper functioning of masc_common local soft_ending_lookup = { ["ć"] = "ci"; ["dź"] = "dzi"; ["ń"] = "ni"; ["ś"] = "si"; ["ź"] = "zi"; } -- Given a word and a lookup table of accepted endings, -- split the word into a stem and an ending. -- Ending is returned in genitive form, i.e. soft consonants -- and digraphs such as ć, ś, dź are converted to midword -- i-forms ci, si, dzi. local function split_stem(word, lookup) -- match the longest possible ending local last, last_gen local limit = math.min(mw.ustring.len(word), 5) for i = -limit, -1 do if not last_gen then last = mw.ustring.sub(word, i) if lookup[last] or soft_ending_lookup[last] then last_gen = soft_ending_lookup[last] or last end end end if last_gen then local stem = mw.ustring.sub(word, 1, -mw.ustring.len(last)-1) return stem, last_gen else return nil, nil end end local function check_split(stem, last) if not stem then error("nil stem encountered in declension pattern") end if not last then error("nil ending encountered in declension pattern") end end local function handle_overrides(pargs, declinfo, ovinfo) -- process cases in order local ret = {} local singpl = { "s", "p" } for i = 1, 14 do local caseno = math.floor((i+1)/2) local sp = 2 - (i % 2) local case_key = cases[caseno].key .. singpl[sp] if pargs[case_key] then ret[case_key] = pargs[case_key] if ovinfo[case_key] then for dummy, v in pairs(ovinfo[case_key]) do ret[v] = pargs[case_key] end end elseif not ret[case_key] then ret[case_key] = declinfo[case_key] end end return ret end -- This table will hold patterns local patterns = {} -- ----------------------------------------------------------------------------- -- -------------------------- Masculine declension ----------------------------- -- ----------------------------------------------------------------------------- -- accepted masculine endings in genitive singular form local masc_endings = make_lookup_table( "acz b bi c ch ci ciec ciel cz d dz dzi dziec ek el eł f g giel h iec ieł ik j k kiel l ł m n ni niec p pi r rz rzeł " .. "s si seł siec sł sm sn st sz t unek w wi x z zi ż zd zeł ziec zł zm zn") -- common function for masculine declensions local function masc_common(pattern, stem, last, gens_ending, noms_form, nomp_form, altgenp, explicit_stem) -- verify that the word ending is supported if not masc_endings[last] then -- suppress module error on the template page if not last or not mw.ustring.match(last, "^{{{") then error("Unsupported word ending: " .. (last or "nil")) end end local initial_last = last -- nominative singular local noms_lookup = { bi = "b"; ci = "ć"; dzi = "dź"; ni = "ń"; ["pi"] = "p"; si = "ś"; wi = "w"; zi = "ź"; } if not noms_form then noms_form = stem .. (noms_lookup[last] or last) end -- fix the only exceptions to -iec vowel elision if last == "iec" and (stem == "w" or stem == "p") then if not gens_ending and stem == "p" then gens_ending = "a" end stem = stem .. "ie" last = "c" end -- limited guessing of masculine inanimate endings here -- personal and animate nouns (except for ''wół'') always have "a" local gens_a = make_lookup_table("acz ciec ciel dzi dziec ek el eł iec ieł ik kiel giel ni niec seł siec rz rzeł zeł") if not gens_ending then if gens_a[last] then gens_ending = "a" else gens_ending = "u" end end -- handle the following things here: -- regular vowel elisions -- overlong endings used only for genitive singular guessing, e.g. acz, unek -- x becoming ks in inflected forms -- stem-final ó becoming o in inflected forms local last_lookup = { acz = "cz"; ciec = "c"; ciel = "l"; dziec = "c"; ek = "k"; el = "l"; ["eł"] = "ł"; iec = "c"; ["ieł"] = "ł"; ik = "k"; kiel = "l"; giel = "l"; niec = "c"; ["rzeł"] = "ł"; ["seł"] = "sł"; siec = "c"; unek = "k"; x = "s"; ["zeł"] = "zł"; ziec = "c"; } local stem_add = { acz = "a"; ciec = "ć"; ciel = "cie"; dziec = "dź"; ik = "i"; kiel = "k"; giel = "g"; niec = "ń"; ["rzeł"] = "r"; siec = "ś"; unek = "un"; x = "k"; ziec = "ź"; } stem = stem .. (stem_add[last] or "") last = last_lookup[last] or last if mw.ustring.match(stem, "ó$") and not explicit_stem then stem = mw.ustring.sub(stem, 1, -2) .. "o" end -- genitive singular local gens_form = stem .. last .. gens_ending -- accusative singular local accs_form = (pattern == "m-in") and noms_form or gens_form -- instrumental singular local inss_form if (last == "g") or (last == "k") then inss_form = stem .. last .. "iem" else inss_form = stem .. last .. "em" end -- locative singular local locs_lookup = { b = "bie"; bi = "biu"; c = "cu"; ch = "chu"; ci = "ciu"; cz = "czu"; d = "dzie"; dz = "dzu"; dzi = "dziu"; f = "fie"; g = "gu"; h = "hu"; j = "ju"; k = "ku"; l = "lu"; ["ł"] = "le"; m = "mie"; n = "nie"; ni = "niu"; p = "pie"; ["pi"] = "piu"; r = "rze"; rz = "rzu"; s = "sie"; si = "siu"; ["sł"] = "śle"; sm = "śmie"; sn = "śnie"; st = "ście"; sz = "szu"; t = "cie"; w = "wie"; wi = "wiu"; z = "zie"; zd = "ździe"; zi = "ziu"; ["zł"] = "źle"; zm = "zmie"; zn = "źnie"; ["ż"] = "żu"; -- the -zm ending should not be palatalized, since it normally occurs -- in borrowed nouns such as "marazm", "komunizm", "faszyzm" } local locs_form = stem .. (locs_lookup[last] or last) -- vocative singular is the same as locative singular, with the exception of -iec local vocs_form = locs_form if pattern == "m-pr" and mw.ustring.match(initial_last, "iec$") then vocs_form = stem .. "cze" end -- nominative plural -- accusative and vocative plural are the same if not nomp_form then local nomp_e_ending = make_lookup_table("bi c ci cz dz dzi j l ni pi rz si sz wi zi ż") if (last == "g") or (last == "k") then nomp_form = stem .. last .. "i" elseif nomp_e_ending[last] then nomp_form = stem ..last .. "e" else nomp_form = stem .. last .. "y" end end -- genitive plural local genp_form if mw.ustring.match(last, "i$") and (last ~= "pi") then genp_form = stem .. last elseif (last == "l") then genp_form = stem .. last .. "i" elseif (last == "j") then genp_form = stem .. last .. "ów" if not altgenp or (altgenp == "") then altgenp = stem .. "i" end elseif (last == "cz") or (last == "rz") or (last == "sz") or (last == "ż") then genp_form = stem .. last .. "y" else genp_form = stem .. last .. "ów" end if nonempty(altgenp) then genp_form = genp_form .. "/" .. altgenp end local deprecate_nomp_form = "" if pattern == "m-pr" then local nomp_e_ending = make_lookup_table("bi c ci cz dz dzi j l ni pi rz si sz wi zi ż") if (last == "g") or (last == "k") then deprecate_nomp_form = stem .. last .. "i" elseif nomp_e_ending[last] then deprecate_nomp_form = stem ..last .. "e" else deprecate_nomp_form = stem .. last .. "y" end end -- accusative plural - same as genitive or nominative depending on animacy local accp_form = (pattern == "m-pr") and genp_form or nomp_form local full_nomp_form = ((pattern == "m-pr") and deprecate_nomp_form ~= nomp_form and nomp_form .. "/" .. deprecate_nomp_form .. " (deprecative)") or nomp_form return { noms = noms_form; nomp = full_nomp_form; gens = gens_form; genp = genp_form; dats = stem .. last .. "owi"; datp = stem .. last .. "om"; accs = accs_form; accp = accp_form; inss = inss_form; insp = stem .. last .. "ami"; locs = locs_form; locp = stem .. last .. "ach"; vocs = vocs_form; vocp = nomp_form; } end -- masculine inanimate nouns, e.g. bruk, beton, słup, szczaw, kurnik -- default genitive singular ending is "u", but "a" endings are common as well patterns["m-in"] = function (pargs, word) local stem, last = split_stem(word, masc_endings) local explicit_stem = false if nonempty(pargs[2]) then stem = pargs[1] or "" last = pargs[2] explicit_stem = true end local gens_ending = pargs[3] or gens_ending local noms_form = nonempty(pargs[4]) local altgenp = nonempty(pargs[5]) local declinfo = masc_common("m-in", stem, last, gens_ending, noms_form, nil, altgenp, explicit_stem) return handle_overrides(pargs, declinfo, { noms = {"accs"}; locs = {"vocs"}; nomp = {"accp", "vocp"} }) end -- masculine animate nouns, e.g. bocian, dzik, jeleń patterns["m-anml"] = function (pargs, word) local stem, last = split_stem(word, masc_endings) local explicit_stem = false if nonempty(pargs[2]) then stem = pargs[1] or "" last = pargs[2] explicit_stem = true end local noms_form = nonempty(pargs[3]) local altgenp = nonempty(pargs[4]) local declinfo = masc_common("m-anml", stem, last, "a", noms_form, nil, altgenp, explicit_stem) return handle_overrides(pargs, declinfo, { gens = {"accs"}; locs = {"vocs"}; nomp = {"accp", "vocp"} }) end -- masculine personal nouns, e.g. policjant, sknerus, polityk patterns["m-pr"] = function (pargs, word) if not pargs[1] and not pargs[2] then if mw.ustring.match(word, "a$") then return patterns["m-pr-a"](pargs, word) elseif mw.ustring.match(word, "[yi]$") then return patterns["m-pr-adj"](pargs, word) elseif mw.ustring.match(word, "nin$") then return patterns["m-pr-nin"](pargs, word) end end local stem, last = split_stem(word, masc_endings) local explicit_stem = false if nonempty(pargs[2]) then stem = pargs[1] or "" last = pargs[2] or "" explicit_stem = true end local nomp_form = nonempty(pargs[3]) or nonempty(pargs.nomp) local noms_form = nonempty(pargs[4]) or nonempty(pargs.noms) local altgenp = nonempty(pargs[5]) -- note: this is only a default, and will need to be overridden often if not nomp_form then nomp_lookup = { acz = "acze"; -- palacz ch = "chowie"; ci = "cie"; ciec = "ćcy"; cz = "cze"; ciel = "ciele"; -- eunuch, cieć, ?, ?, nauczyciel d = "dzi", dziec = "dźcy"; -- kloszard, jeździec ek = "kowie"; el = "ele"; -- świadek, ? f = "fowie"; -- szeryf g = "dzy"; -- szpieg h = "howie"; -- druh iec = "cy"; ik = "icy"; -- pogrobowiec, czytelnik j = "je"; -- lokaj k = "cy"; -- alkoholik l = "le"; ["ł"] = "łowie"; -- ?, apostoł m = "mi"; -- pielgrzym n = "ni"; ni = "nie"; niec = "ńcy"; -- kompan, leń, jeniec p = "pi"; -- chłop r = "rzy"; rz = "rze"; -- konduktor, murarz s = "si"; si = "sie"; siec = "ścy"; sz = "sze"; -- ordynans, rabuś, ?, jarosz t = "ci"; -- policjant z = "zi"; zi = "zie"; ziec = "źcy"; ["ż"] = "żowie"; -- intruz, kniaź, ?, mąż } if not nomp_lookup[last] then error("Unsupported word ending: " .. last .. "; please define the nominative plural form") end if last == "g" and mw.ustring.match(stem, "lo$") then nomp_form = stem .. "dzy/" .. stem .. "gowie" else nomp_form = stem .. nomp_lookup[last] end end local declinfo = masc_common("m-pr", stem, last, "a", noms_form, nomp_form, altgenp, explicit_stem) return handle_overrides(pargs, declinfo, { gens = {"accs"}; locs = {"vocs"}; nomp = {"vocp"}; genp = {"accp"} }) end -- masculine personal nouns with adjectival declension -- e.g. radny, łowczy, salowy patterns["m-pr-adj"] = function (pargs, title) local word = pargs[1] or title if mw.ustring.match(word, "^{{{") then word = "przykładowy" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[1]; nomp = decl[4]; gens = decl[6]; genp = decl[8]; dats = decl[9]; datp = decl[10]; accs = decl[6]; accp = decl[8]; inss = decl[12]; insp = decl[13]; locs = decl[12]; locp = decl[8]; vocs = decl[1]; vocp = decl[4]; } return handle_overrides(pargs, declinfo, { noms = {"vocs"}; gens = {"accs"}; nomp = {"vocp"}; genp = {"accp", "locp"} }) end -- masculine personal nouns that end in -a -- e.g. stażysta, dawca, banita patterns["m-pr-a"] = function (pargs, word) local word_no_a = mw.ustring.match(word, "^(.*)a$") or "" local endings = make_lookup_table("b bi c ch d g j p r st t zd zn ż") local stem, last = split_stem(word_no_a, endings) stem = nonempty(pargs[1]) or stem last = nonempty(pargs[2]) or last if not endings[last] then -- suppress module error on the template page if not mw.ustring.match(last, "^{{{") then error("Unsupported word ending: " .. last) end end local gens_form = stem .. last .. "y" if last == "j" then gens_form = stem .. "i" elseif last == "g" then gens_form = stem .. "gi" end local dats_lookup = { b = "bie"; -- Barnaba bi = "bi"; c = "cy"; -- zdrajca ch = "sze"; -- monarcha d = "dzie"; -- nomada (?) g = "dze"; -- sługa j = "i"; -- kaznodzieja p = "pie"; -- satrapa r = "rze"; -- sknera st = "ście"; -- starosta t = "cie"; -- idiota zd = "ździe"; -- gazda zn = "źnie"; -- mężczyzna ["ż"] = "ży"; -- doża } local dats_form = stem .. (dats_lookup[last] or last) local nomp_lookup = { b = "bowie"; bi = "biowie"; c = "cy"; ch = "chowie"; d = "dzi"; g = "dzy"; j = "je"; p = "powie"; r = "rzy"; st = "ści"; t = "ci"; zd = "zdowie"; zn = "źni"; ["ż"] = "żowie"; } local nomp_form = stem .. (nomp_lookup[last] or (last .. "i")) local genp_form = stem .. last .. "ów" if last == "zn" then genp_form = stem .. last end local deprecate_nomp_form = "" local nomp_e_ending = make_lookup_table("bi c ci cz dz dzi j l ni pi rz si sz wi zi ż") if (last == "g") or (last == "k") then deprecate_nomp_form = stem .. last .. "i" elseif nomp_e_ending[last] then deprecate_nomp_form = stem ..last .. "e" else deprecate_nomp_form = stem .. last .. "y" end local full_nomp_form = (deprecate_nomp_form ~= nomp_form and nomp_form .. "/" .. deprecate_nomp_form .. " (deprecative)") or nomp_form -- TODO: alternative adjectival declension for -bia local declinfo = { noms = stem .. last .. "a"; nomp = full_nomp_form; gens = gens_form; genp = genp_form; dats = dats_form; datp = stem .. last .. "om"; accs = stem .. last .. "ę"; accp = genp_form; inss = stem .. last .. "ą"; insp = stem .. last .. "ami"; locs = dats_form; locp = stem .. last .. "ach"; vocs = stem .. last .. "o"; vocp = nomp_form; } return handle_overrides(pargs, declinfo, { dats = {"locs"}; nomp = {"vocp"}; genp = {"accp"} }) end -- masculine nouns ending in -log, both personal and inanimate -- inanimate form is chosen when the first parameter is empty patterns["log"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)log$") or "" local nomp_form = nonempty(pargs[2]) local inanimate = not nonempty(pargs[1]) if not nomp_form then if inanimate then nomp_form = stem .. "logi" else nomp_form = stem .. "lodzy/" .. stem .. "logowie" end end local gens_form = stem .. "loga" if inanimate then gens_form = stem .. "logu" end local accs_form = stem .. "loga" if inanimate then accs_form = stem .. "log" end local declinfo = { noms = stem .. "log"; nomp = nomp_form; gens = gens_form; genp = stem .. "logów"; dats = stem .. "logowi"; datp = stem .. "logom"; accs = accs_form; accp = stem .. "logów"; inss = stem .. "logiem"; insp = stem .. "logami"; locs = stem .. "logu"; locp = stem .. "logach"; vocs = stem .. "logu"; vocp = nomp_form; } return handle_overrides(pargs, declinfo, { locs = {"vocs"}; nomp = {"vocp"}; genp = {"accp"} }) end -- masculine personal nouns ending with -nin, e.g. Rosjanin, łodzianin -- popular for demonyms patterns["m-pr-nin"] = function (pargs, word) local stem = nonempty(pargs[1]) or mw.ustring.match(word, "^(.*)nin$") local genp_ending = pargs[2] or "n" local declinfo = { noms = stem .. "nin"; nomp = stem .. "nie"; gens = stem .. "nina"; genp = stem .. genp_ending; dats = stem .. "ninowi"; datp = stem .. "nom"; accs = stem .. "nina"; accp = stem .. genp_ending; inss = stem .. "ninem"; insp = stem .. "nami"; locs = stem .. "ninie"; locp = stem .. "nach"; vocs = stem .. "ninie"; vocp = stem .. "nie"; } return handle_overrides(pargs, declinfo, { gens = {"accs"}; locs = {"vocs"}; nomp = {"vocp"}; genp = {"accp"} }) end -- masculine inanimate adjectives in noun phrases patterns["adj-m-in"] = function (pargs, word) word = nonempty(pargs[1]) or word if mw.ustring.match(word, "^{{{") then word = "przykładowy" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[1]; nomp = decl[5]; gens = decl[6]; genp = decl[8]; dats = decl[9]; datp = decl[10]; accs = decl[1]; accp = decl[5]; inss = decl[12]; insp = decl[13]; locs = decl[12]; locp = decl[8]; vocs = decl[1]; vocp = decl[5]; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; inss = {"locs"}; nomp = {"accp", "vocp"}; genp = {"locp"} }) end -- masculine animate adjectives in noun phrases patterns["adj-m-anml"] = function (pargs, word) word = nonempty(pargs[1]) or word if mw.ustring.match(word, "^{{{") then word = "przykładowy" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[1]; nomp = decl[5]; gens = decl[6]; genp = decl[8]; dats = decl[9]; datp = decl[10]; accs = decl[6]; accp = decl[5]; inss = decl[12]; insp = decl[13]; locs = decl[12]; locp = decl[8]; vocs = decl[1]; vocp = decl[5]; } return handle_overrides(pargs, declinfo, { noms = {"vocs"}; gens = {"accs"}; inss = {"locs"}; nomp = {"accp", "vocp"}; genp = {"locp"} }) end -- masculine personal adjectives in noun phrases are identical -- to masculine personal adjectival declension -- ----------------------------------------------------------------------------- -- -------------------------- Feminine declension ------------------------------ -- ----------------------------------------------------------------------------- local fem_endings = make_lookup_table( "b bi c ch ci cz d dz dzi dż f g h j k l ł m n ni p pi r rz " .. "s si sł sm sn st sz t w wi z zd zi zł zm zn ż") -- most feminine nouns ending in -a -- note that some nouns ending in -ia have this declension and others -- follow the "f-ia" pattern - it's impossible to tell from the word alone. patterns["f"] = function (pargs, word) -- to handle pluralia tantum as well local word_no_a = mw.ustring.match(word, "^(.*)[aeiy]$") local pars3 = pargs[1] and pargs[2] and pargs[3] local nopars = not pargs[1] and not pargs[2] and not pargs[3] -- 2 positional parameters given OR a at the and -> use a-final declension -- 3+ positional parameters given OR consonant at the end -> use f-softcons if nopars then if mw.ustring.match(word, "ia$") then native_ia = mw.ustring.match(word, "[bcdjklłrśtwzź]nia$") native_ia = native_ia or mw.ustring.match(word, "[csz]ia$") if not native_ia then return patterns["f-ia"](pargs, word) end elseif mw.ustring.match(word, "ni$") then return patterns["f-ni"](pargs, word) end end if pars3 or not word_no_a then return patterns["f-softcons"](pargs, word) end word_no_a = word_no_a or word local stem, last = split_stem(word_no_a, fem_endings) stem = nonempty(pargs[1]) or stem last = nonempty(pargs[2]) or last if not fem_endings[last] then -- suppress module error on the template page if not mw.ustring.match(last, "^{{{") then error("Unsupported word ending: " .. last) end end local soft_endings = make_lookup_table("bi ci dzi ni pi si wi zi") local gens_form = stem .. last .. "y" if soft_endings[last] then gens_form = stem .. last elseif last == "j" then if mw.ustring.match(stem, "[aąeęioóuy]$") then gens_form = stem .. "i" else gens_form = stem .. last .. "i" end elseif (last == "g") or (last == "k") or (last == "l") then gens_form = stem .. last .. "i" end local dats_lookup = { b = "bie"; bi = "bi"; c = "cy"; ch = "sze"; ci = "ci"; cz = "czy"; d = "dzie"; dz = "dzy"; dzi = "dzi"; ["dż"] = "dży"; f = "fie"; g = "dze"; h = "że"; j = "ji"; k = "ce"; l = "li"; ["ł"] = "le"; m = "mie"; n = "nie"; ni = "ni"; p = "pie"; ["pi"] = "pi"; r = "rze"; rz = "rzy"; s = "sie"; si = "si"; ["sł"] = "śle"; sm = "śmie"; sn = "śnie"; st = "ście"; sz = "szy"; t = "cie"; w = "wie"; wi = "wi"; z = "zie"; zd = "ździe"; zi = "zi"; ["zł"] = "źle"; zm = "zmie"; zn = "źnie"; ["ż"] = "ży"; -- -zm should not be palatalized } local dats_form = stem .. (dats_lookup[last] or last) if last == "j" and mw.ustring.match(stem, "[aąeęioóuy]$") then dats_form = stem .. "i" end local nomp_e_ending = make_lookup_table("bi c ci cz dz dzi dż j l ni pi rz si sz wi zi ż") local nomp_form = stem .. last .. "y" if (last == "g") or (last == "k") then nomp_form = stem .. last .. "i" elseif nomp_e_ending[last] then nomp_form = stem .. last .. "e" end local genp_form = stem .. last if last == "j" then if mw.ustring.match(stem, "[aąeęioóuy]$") then -- zgraja, breja, żmija, koja, szuja, chryja -> -- zgraj, brej, żmij, koj, szuj, chryj genp_form = stem .. last else -- e.g. gracja, torsja genp_form = stem .. "ji/" .. stem .. "yj" .. " (archaic)"; end elseif last == "l" then if mw.ustring.match(stem, "[aąeęioóuy]$") then -- hala, tabela, mila, rola, kula genp_form = stem .. "l" else -- hodowla, grobla, bernikla genp_form = stem .. "li" end elseif last == "k" then local kstem, klast = split_stem(stem, soft_ending_lookup) if kstem then kstem = kstem .. klast else kstem = stem end if mw.ustring.match(stem, "[aąeęioóuy]$") then genp_form = kstem .. "k" else genp_form = kstem .. "ek" end end local declinfo = { noms = stem .. last .. "a"; nomp = nomp_form; gens = gens_form; genp = genp_form; dats = dats_form; datp = stem .. last .. "om"; accs = stem .. last .. "ę"; accp = nomp_form; inss = stem .. last .. "ą"; insp = stem .. last .. "ami"; locs = dats_form; locp = stem .. last .. "ach"; vocs = stem .. last .. "o"; vocp = nomp_form; } return handle_overrides(pargs, declinfo, { dats = {"locs"}; nomp = {"accp", "vocp"} }) end -- feminine nouns ending with a consonant, e.g. stal, sól, brew patterns["f-softcons"] = function (pargs, title) local endings = make_lookup_table("c ć cz dz dź ew iew j l ń rz ś sz w z ż ź") local accepted_lasts = make_lookup_table("c ci cz dz dzi j l ni rz si sz wi zi ż") local stem, last = split_stem(title, endings) local explicit_stem = false stem = nonempty(pargs[1]) or stem last = nonempty(pargs[2]) or last if nonempty(pargs[2]) then stem = pargs[1] or "" last = pargs[2] or "" explicit_stem = true end local nomp_ending = pargs[3] -- may be empty local noms_form = nonempty(pargs[4]) -- Narew, brukiew, żagiew, brew - elide -e- or -ie- if last == "iew" or last == "ew" then if not noms_form then noms_form = stem .. last end last = "wi" end if last == "w" or last == "z" then last = last .. "i" end if not accepted_lasts[last] then -- suppress module error on the template page if not last or not mw.ustring.match(last, "^{{{") then error("Unsupported word ending: " .. (last or "nil")) end end -- nominative singular if not noms_form or (noms_form == "") then local noms_lookup = { ci = "ć"; dzi = "dź"; ni = "ń"; si = "ś"; wi = "w"; zi = "ź"; } noms_form = stem .. (noms_lookup[last] or last) end -- Stem-final ó becoming o in inflected forms if mw.ustring.match(stem, "ó$") and not explicit_stem then stem = mw.ustring.sub(stem, 1, -2) .. "o" end -- genitive singular local gens_form = stem .. last local gens_y_ending = make_lookup_table("c cz dz sz rz ż") if last == "j" then gens_form = stem .. "i" elseif last == "l" then gens_form = gens_form .. "i" elseif gens_y_ending[last] then gens_form = gens_form .. "y" end -- nominative plural if not nomp_ending then if last == "ci" then -- some words have -e, but this is a lot more common nomp_ending = "" else nomp_ending = "e" end end -- this is trivial, but used in 3 places in the table local nomp_form = stem .. last .. nomp_ending; local declinfo = { noms = noms_form; nomp = nomp_form; gens = gens_form; genp = gens_form; dats = gens_form; datp = stem .. last .. "om"; accs = noms_form; accp = nomp_form; inss = stem .. last .. "ą"; insp = stem .. last .. "ami"; locs = gens_form; locp = stem .. last .. "ach"; vocs = gens_form; vocp = nomp_form; } return handle_overrides(pargs, declinfo, { noms = {"accs"}; gens = {"dats", "locs", "vocs", "genp"}; nomp = {"accp", "vocp"} }) end -- feminine nouns with adjectival declension patterns["f-adj"] = function (pargs, title) local word = nonempty(pargs[1]) or title if mw.ustring.match(word, "^{{{") then word = "przykładowa" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[2]; nomp = decl[5]; gens = decl[7]; genp = decl[8]; dats = decl[7]; datp = decl[10]; accs = decl[11]; accp = decl[5]; inss = decl[11]; insp = decl[13]; locs = decl[7]; locp = decl[8]; vocs = decl[2]; vocp = decl[5]; } return handle_overrides(pargs, declinfo, { gens = {"dats", "locs"}; accs = {"inss"}; nomp = {"accp", "vocp"}; genp = {"locp"} }) -- "vocs" may not always be equal to "noms" (e.g. "teściowa") end -- feminine nouns ending with -ja, e.g. fuzja, anomizja, animacja -- obsolete - "f" handles them as well patterns["f-ja"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)ja$") local yj = "yj" if pargs[2] and (pargs[2] ~= "") then yj = "ij" end genp_form = stem .. "ji/" .. stem .. yj .. " (archaic)"; local declinfo = { noms = stem .. "ja"; nomp = stem .. "je"; gens = stem .. "ji"; genp = genp_form; dats = stem .. "ji"; datp = stem .. "jom"; accs = stem .. "ję"; accp = stem .. "je"; inss = stem .. "ją"; insp = stem .. "jami"; locs = stem .. "ji"; locp = stem .. "jach"; vocs = stem .. "jo"; vocp = stem .. "je"; } return handle_overrides(pargs, declinfo, { gens = {"dats", "locs"}; nomp = {"accp", "vocp"} }) end -- most feminine nouns ending with -ia, e.g. mafia, kopia, balia -- note that some nouns follow the "f" pattern instead, e.g. konopia, głębia patterns["f-ia"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)ia$") local oldgenp = stem .. "ij" if mw.ustring.match(stem, "[dtr]$") then oldgenp = stem .. "yj" end local genp_form = stem .. "ii/" .. oldgenp .. " (archaic)"; local declinfo = { noms = stem .. "ia"; nomp = stem .. "ie"; gens = stem .. "ii"; genp = genp_form; dats = stem .. "ii"; datp = stem .. "iom"; accs = stem .. "ię"; accp = stem .. "ie"; inss = stem .. "ią"; insp = stem .. "iami"; locs = stem .. "ii"; locp = stem .. "iach"; vocs = stem .. "io"; vocp = stem .. "ie"; } return handle_overrides(pargs, declinfo, { gens = {"dats", "locs"}; nomp = {"accp", "vocp"} }) end -- feminine nouns ending in -ni, e.g. mistrzyni, mędrczyni patterns["f-ni"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)ni$") local declinfo = { noms = stem .. "ni"; nomp = stem .. "nie"; gens = stem .. "ni"; genp = stem .. "ń"; dats = stem .. "ni"; datp = stem .. "niom"; accs = stem .. "nię"; accp = stem .. "nie"; inss = stem .. "nią"; insp = stem .. "niami"; locs = stem .. "ni"; locp = stem .. "niach"; vocs = stem .. "ni"; vocp = stem .. "nie"; } return handle_overrides(pargs, declinfo, { noms = {"gens", "dats", "locs", "vocs"}; nomp = {"accp", "vocp"} }) end -- feminine adjectives in noun phrases patterns["adj-f"] = function (pargs, title) local word = nonempty(pargs[1]) or title if mw.ustring.match(word, "^{{{") then word = "przykładowa" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[2]; nomp = decl[5]; gens = decl[7]; genp = decl[8]; dats = decl[7]; datp = decl[10]; accs = decl[11]; accp = decl[5]; inss = decl[11]; insp = decl[13]; locs = decl[7]; locp = decl[8]; vocs = decl[2]; vocp = decl[5]; } return handle_overrides(pargs, declinfo, { noms = {"vocs"}; gens = {"dats", "locs"}; accs = {"inss"}; nomp = {"accp", "vocp"}; genp = {"locp"} }) end -- ----------------------------------------------------------------------------- -- -------------------------- Neuter declension ----------------------------- -- ----------------------------------------------------------------------------- -- neuter nouns ending in -o, e.g. jajko, jarzmo, gusło, cudo patterns["n"] = function (pargs, word) if pargs[1] and mw.ustring.match(pargs[1], "^{{{") then word = "jajko" end -- forward to other patterns depending on the last letter if not nonempty(pargs[1]) and not nonempty(pargs[2]) then if mw.ustring.match(word, "e$") then return patterns["n-e"](pargs, word) elseif mw.ustring.match(word, "ę$") then return patterns["n-ę"](pargs, word) elseif mw.ustring.match(word, "um$") then return patterns["n-um"](pargs, word) end end local word_no_o = mw.ustring.match(word, "^(.*)o$") local endings = make_lookup_table( "b bn c ch d f g gn j k kn l ł m mn n nd p r rz rzm " .. "s sk sł sm sn st t tt tw w wn z zd zł zm zn zz") local stem, last if word_no_o then stem, last = split_stem(word_no_o, endings) end stem = nonempty(pargs[1]) or stem last = nonempty(pargs[2]) or last local genp_form = nonempty(pargs[3]) if not endings[last] then -- suppress module error on the template page if not mw.ustring.match(last, "^{{{") then error("Unsupported word ending: " .. last) end end local inss_form = stem .. last .. "em" if last == "g" or last == "k" then inss_form = stem .. last .. "iem" end local locs_lookup = { b = "bie"; bn = "bnie"; c = "cu"; ch = "chu"; d = "dzie"; f = "fie"; g = "gu"; gn = "gnie"; j = "ju"; k = "ku"; kn = "knie"; l = "lu"; ["ł"] = "le"; m = "mie"; mn = "mnie"; n = "nie"; nd = "ndzie"; p = "pie"; r = "rze"; rz = "rzu"; rzm = "rzmie"; -- piórze, scherzu, jarzmie s = "sie"; sk = "sku"; ["sł"] = "śle"; sm = "śmie"; sn = "śnie"; st = "ście"; t = "cie"; tt = "tcie"; tw = "twie"; w = "wie"; wn = "wnie"; z = "zie"; zd = "ździe"; ["zł"] = "źle"; zm = "źmie"; zn = "źnie"; zz = "zzu"; } locs_form = stem .. (locs_lookup[last] or (last .. "u")) if not genp_form then if last == "sn" or last == "zn" then genp_form = stem .. mw.ustring.sub(last, 1, 1) .. "en" -- e.g. krosno -> krosen elseif mw.ustring.match(last, "^.n$") then genp_form = stem .. mw.ustring.sub(last, 1, 1) .. "ien" -- e.g. bagno -> bagien elseif last == "tw" or last == "sk" or mw.ustring.match(stem, "[aąeęioóuy]$") then genp_form = stem .. last -- e.g. bogactwo -> bogactw, dyktando -> dyktand (nd treated as digraph) else if mw.ustring.match(stem, "[gk]$") then genp_form = stem .. "ie" .. last -- e.g. szkło -> szkieł else genp_form = stem .. "e" .. last -- e.g. jajko -> jajek end end end local declinfo = { noms = stem .. last .. "o"; nomp = stem .. last .. "a"; gens = stem .. last .. "a"; genp = genp_form; dats = stem .. last .. "u"; datp = stem .. last .. "om"; accs = stem .. last .. "o"; accp = stem .. last .. "a"; inss = inss_form; insp = stem .. last .. "ami"; locs = locs_form; locp = stem .. last .. "ach"; vocs = stem .. last .. "o"; vocp = stem .. last .. "a"; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; gens = {"nomp", "accp", "vocp"}; nomp = {"accp", "vocp"} }) end -- neuter nouns ending in -e patterns["n-e"] = function (pargs, word) local word_no_e = mw.ustring.match(word, "^(.*)e$") local endings = make_lookup_table("bi c ci cz dz dzi fi j l mi ni pi rz si sz wi zi ż") local stem, last if word_no_e then stem, last = split_stem(word_no_e, endings) end if nonempty(pargs[1]) then stem = pargs[1] last = "" end local genp_lookup = { ci = "ć"; cz = "czy"; ni = "ń"; rz = "rzy"; sz = "szy"; ["ż"] = "ży"; } local genp_form = pargs[3] or (stem .. (genp_lookup[last] or last)) local sl = stem .. last local declinfo = { noms = sl .. "e"; nomp = sl .. "a"; gens = sl .. "a"; genp = genp_form; dats = sl .. "u"; datp = sl .. "om"; accs = sl .. "e"; accp = sl .. "a"; inss = sl .. "em"; insp = sl .. "ami"; locs = sl .. "u"; locp = sl .. "ach"; vocs = sl .. "e"; vocp = sl .. "a"; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; gens = {"nomp", "accp", "vocp"}; dats = {"locs"}; nomp = {"accp", "vocp"} }) end -- neuter nouns ending in -ę but not in -mię, e.g. kocię, szczenię, dziecię patterns["n-ę"] = function (pargs, title) local mstem = mw.ustring.match(title, "^(.*)mię$") if mstem then pargs[1] = mstem return patterns["n-mię"](pargs, title) end local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)ę$") local declinfo = { noms = stem .. "ę"; nomp = stem .. "ęta"; gens = stem .. "ęcia"; genp = stem .. "ąt"; dats = stem .. "ęciu"; datp = stem .. "ętom"; accs = stem .. "ę"; accp = stem .. "ęta"; inss = stem .. "ęciem"; insp = stem .. "ętami"; locs = stem .. "ęciu"; locp = stem .. "ętach"; vocs = stem .. "ę"; vocp = stem .. "ęta"; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; dats = {"locs"}; nomp = {"accp", "vocp"} }) end -- neuter nouns ending in -mię, e.g. wymię, znamię, plemię patterns["n-mię"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)mię$") local declinfo = { noms = stem .. "mię"; nomp = stem .. "miona"; gens = stem .. "mienia"; genp = stem .. "mion"; dats = stem .. "mieniu"; datp = stem .. "mionom"; accs = stem .. "mię"; accp = stem .. "miona"; inss = stem .. "mieniem"; insp = stem .. "mionami"; locs = stem .. "mieniu"; locp = stem .. "mionach"; vocs = stem .. "mię"; vocp = stem .. "miona"; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; dats = {"locs"}; nomp = {"accp", "vocp"} }) end -- neuter nouns with adjectival declension, e.g. bykowe patterns["n-adj"] = function (pargs, title) local word = nonempty(pargs[1]) or title if mw.ustring.match(word, "^{{{") then word = "przykładowe" end local decl = m_adj.autoinflect(word) local declinfo = { noms = decl[3]; nomp = decl[5]; gens = decl[6]; genp = decl[8]; dats = decl[9]; datp = decl[10]; accs = decl[3]; accp = decl[5]; inss = decl[12]; insp = decl[13]; locs = decl[12]; locp = decl[8]; vocs = decl[3]; vocp = decl[5]; } return handle_overrides(pargs, declinfo, { noms = {"accs", "vocs"}; inss = {"locs"}; nomp = {"accp", "vocp"}; genp = {"locp"} }) end -- neuter nouns ending in -um, e.g. liceum, gimnazjum, kryterium -- mostly nouns borrow from ancient Greek patterns["n-um"] = function (pargs, title) local stem = nonempty(pargs[1]) or mw.ustring.match(title, "^(.*)um$") local declinfo = { noms = stem .. "um"; nomp = stem .. "a"; gens = stem .. "um"; genp = stem .. "ów"; dats = stem .. "um"; datp = stem .. "om"; accs = stem .. "um"; accp = stem .. "a"; inss = stem .. "um"; insp = stem .. "ami"; locs = stem .. "um"; locp = stem .. "ach"; vocs = stem .. "um"; vocp = stem .. "a"; } return handle_overrides(pargs, declinfo, { nomp = {"accp", "vocp"} }) end -- highly irregular nouns patterns["irreg"] = function (pargs, title) local word = make_lookup_table("brat dziecko ksiądz książę rok arcyksiążę") if not word[title] then if not mw.ustring.match(title, "^{{{") then error("Unsupported word") end end -- brat if title == "brat" then noms_form = "brat" gens_form = "brata" dats_form = "bratu" accs_form = "brata" inss_form = "bratem" locs_form = "bracie" vocs_form = "bracie" nomp_form = "bracia" genp_form = "braci" datp_form = "braciom" accp_form = "braci" insp_form = "braćmi" locp_form = "braciach" vocp_form = "bracia" end -- dziecko if title == "dziecko" then noms_form = "dziecko" gens_form = "dziecka" dats_form = "dziecku" accs_form = "dziecko" inss_form = "dzieckiem" locs_form = "dziecku" vocs_form = "dziecko" nomp_form = "dzieci" genp_form = "dzieci" datp_form = "dzieciom" accp_form = "dzieci" insp_form = "dziećmi" locp_form = "dzieciach" vocp_form = "dzieci" end --ksiądz if title == "ksiądz" then noms_form = "ksiądz" gens_form = "księdza" dats_form = "księdzu" accs_form = "księdza" inss_form = "księdzem" locs_form = "księdzu" vocs_form = "księże" nomp_form = "księża" genp_form = "księży" datp_form = "księżom" accp_form = "księży" insp_form = "księżmi" locp_form = "księżach" vocp_form = "księża" end --książę if title == "książę" then noms_form = "książę" gens_form = "księcia" dats_form = "księciu" accs_form = "księcia" inss_form = "księciem" locs_form = "księciu" vocs_form = "książę" nomp_form = "książęta" genp_form = "książąt" datp_form = "książętom" accp_form = "książąt" insp_form = "książętami" locp_form = "książętach" vocp_form = "książęta" end -- rok if title == "rok" then noms_form = "rok" gens_form = "roku" dats_form = "rokowi" accs_form = "rok" inss_form = "rokiem" locs_form = "roku" vocs_form = "roku" nomp_form = "lata" genp_form = "lat" datp_form = "latom" accp_form = "lata" insp_form = "latami" locp_form = "latach" vocp_form = "lata" end --arcyksiążę if title == "arcyksiążę" then noms_form = "arcyksiążę" gens_form = "arcyksięcia" dats_form = "arcyksięciu" accs_form = "arcyksięcia" inss_form = "arcyksięciem" locs_form = "arcyksięciu" vocs_form = "arcyksiążę" nomp_form = "arcyksiążęta" genp_form = "arcyksiążąt" datp_form = "arcyksiążętom" accp_form = "arcyksiążąt" insp_form = "arcyksiążętami" locp_form = "arcyksiążętach" vocp_form = "arcyksiążęta" end local declinfo = { noms = noms_form; nomp = nomp_form; gens = gens_form; genp = genp_form; dats = dats_form; datp = datp_form; accs = accs_form; accp = accp_form; inss = inss_form; insp = insp_form; locs = locs_form; locp = locp_form; vocs = vocs_form; vocp = vocp_form; } return handle_overrides(pargs, declinfo, {}) end -- indeclinable pattern, i.e. same word for all cases patterns["indec"] = function (pargs, title) local word = nonempty(pargs[1]) or title local declinfo = {} for i = 1, 7 do for _, col in ipairs(noun_cols) do declinfo[cases[i].key .. col.key] = word end end return handle_overrides(pargs, declinfo, {}) end -- shorthands patterns["nin"] = patterns["m-pr-nin"] patterns["ia"] = patterns["fem-ia"] -- aliases for adjectives in phrases patterns["adj-m-pr"] = patterns["m-pr-adj"] patterns["adj-n"] = patterns["n-adj"] -- used for autodetection of adjective genders in phrases local function pattern_gender(pattern) if pattern == "m-in" or pattern == "adj-m-in" then return "m-in" elseif pattern == "m-an" or pattern == "adj-m-an" or pattern == "m-anml" or pattern == "adj-m-anml" then return "m-anml" elseif string.match(pattern, "^m-pr") or pattern == "adj-m-pr" then return "m-pr" elseif string.match(pattern, "^f") or pattern == "adj-f" then return "f" elseif string.match(pattern, "^n") or pattern == "adj-n" then return "n" end return nil end -- generate inflected forms given pattern, parameters, and full word -- returned words do not contain links function export.autoinflect(pattern, pargs, word) if not pattern then error("Declension pattern not specified") end if mw.ustring.match(pattern, "^{{{") then pattern = "m-in" end if not patterns[pattern] then error("Invalid declension pattern: " .. pattern) end return patterns[pattern](pargs, pargs["lemma"] or word) end local function make_substitutable_table(pargs, declinfo, preproc) local tantum = normalize_tantum(pargs) if mw.isSubsting() then if tantum == "s" or tantum == "p" then local tname = "sing" if tantum == "p" then tname = "pl" end local rows = {} for i = 1, 7 do local case_key = cases[i].key .. tantum table.insert(rows, ("| <!-- %s --> %s"):format(case_key, m_links.remove_links(declinfo[case_key]))) end return "{{pl-decl-noun-" .. tname .. "\n" .. table.concat(rows, "\n") .. "\n}}" end local rows = {} for i = 1, 7 do local case_skey = cases[i].key .. "s" local case_pkey = cases[i].key .. "p" table.insert(rows, ("| <!-- %s --> %s"):format(case_skey, m_links.remove_links(declinfo[case_skey]))) table.insert(rows, ("| <!-- %s --> %s"):format(case_pkey, m_links.remove_links(declinfo[case_pkey]))) end return "{{pl-decl-noun\n" .. table.concat(rows, "\n") .. "\n}}" else local cols = noun_cols if tantum == "s" then cols = { noun_cols[1] } elseif tantum == "p" then cols = { noun_cols[2] } end cols = override_col_titles(pargs.heads, cols) if pargs.nocat then tantum = nil end return make_table(declinfo, cols, preproc, pargs.width, pargs.title, tantum, pargs.nolinks) end end -- Generate declension table for a specified declension pattern function export.template_decl_pattern(frame) local args = frame.args local pargs = frame:getParent().args local pagetitle = mw.loadData("Module:headword/data").pagename -- support "num" as fallback for "tantum" to match Latin templates local tantum = pargs.tantum or pargs.num if tantum == "sg" then tantum = "s" elseif tantum == "pl" then tantum = "p" end if get_mode() == 'demo' then pargs = { "{{{1}}}", "{{{2}}}", "{{{3}}}", "{{{4}}}", "{{{5}}}" } end -- if args is empty, use pargs[1] as the pattern name and shift pargs local offset = 0 local pattern = args[1] if not pattern then -- extreme brokenness: table.remove(pargs, 1) has absolutely no effect! -- is this because pargs is somehow immutable? pattern = pargs[1] offset = -1 end local fixed_pargs = {} for key, parg in pairs(pargs) do if type(key) == "number" then local i = key + offset if i >= 1 and parg then fixed_pargs[i] = m_links.remove_links(parg) end else fixed_pargs[key] = m_links.remove_links(parg) end end declinfo = export.autoinflect(pattern, fixed_pargs, pagetitle) return make_substitutable_table(pargs, declinfo, "linkify") end local function push_down_indices(tbl) local ret = {} for index, decl in ipairs(tbl) do for k, v in pairs(decl) do ret[k] = ret[k] or {} table.insert(ret[k], v) end end return ret end -- Generate declension table for a noun phrase function export.template_decl_phrase(frame) local args = frame.args local pargs = frame:getParent().args local page_title = mw.loadData("Module:headword/data").pagename local lemma = pargs["lemma"] or page_title local words = {} if get_mode() == "demo" then pargs = { "adj", "n", "adj" } lemma = "przykładowe wyrażenie rzeczownikowe" end -- split title into words for t in mw.ustring.gmatch(lemma, "[^ ]+") do table.insert(words, t) end local word_args = {} for index, word in ipairs(words) do -- parse arguments to declension patterns word_args[index] = {} local numkey = 1 local arg = pargs[index] or "" for i in mw.ustring.gmatch(arg, "[^!]+") do local param = mw.text.trim(i) local k, v = mw.ustring.match(param, "^([^:]*):(.*)$") if k and v then word_args[index][k] = v else word_args[index][numkey] = param numkey = numkey + 1 end end end local adj_gender = nil for index, word in ipairs(words) do -- find the first gendered pattern and use it to match adjectives if not adj_gender then adj_gender = pattern_gender(word_args[index][1]) end end local result = {} local result_raw = {} for index, word in ipairs(words) do local word_result = {} local pattern = table.remove(word_args[index], 1) if pattern == "adj" then if adj_gender then pattern = "adj-" .. adj_gender else error("Unable to guess adjective gender") end end if not pattern or pattern == "-" then -- indeclinable pattern = "indec" elseif not patterns[pattern] then error("Unrecognized pattern '" .. pattern .. "'") end result_raw[index] = export.autoinflect(pattern, word_args[index], word) result[index] = linkify_info(result_raw[index], altsep, true) end -- rearrange the table so that word indices are at the lower level result_raw = push_down_indices(result_raw) result = push_down_indices(result) -- make table entries for case, v in pairs(result_raw) do local phrase = table.concat(v, " ") if phrase == page_title then -- bold self-link if the phrase is equal to the page title result[case] = "[[" .. page_title .. "]]" else result[case] = table.concat(result[case], " ") -- do not split if linking full phrase declensions result[case] = export.make_links(result[case], nil) end end -- width determination if not pargs.width then local result_concat = {} for case, v in pairs(result_raw) do result_concat[case] = table.concat(v, " ") end pargs.width = guess_width(result_concat, noun_cols) end -- disable linkifying, since we already made per-word links return make_substitutable_table(pargs, result, nil) end return export oyqasjd1ob8r9mp7ehe4qq2ejw1h76p မဝ်ဂျူ:pl-noun/doc 828 295567 396204 2026-06-03T13:22:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module implements {{temp|pl-decl-noun}}, {{temp|pl-decl-noun-sing}}, {{temp|pl-decl-noun-pl}} and {{temp|pl-decl-noun-dual}}. <includeonly> {{module cat|pl}} </includeonly>" 396204 wikitext text/x-wiki This module implements {{temp|pl-decl-noun}}, {{temp|pl-decl-noun-sing}}, {{temp|pl-decl-noun-pl}} and {{temp|pl-decl-noun-dual}}. <includeonly> {{module cat|pl}} </includeonly> h19wzvx6mxozhfg2af3j3gzt2juuxgl ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲပဝ်လာန်ဂမၠိုၚ် 14 295568 396205 2026-06-03T13:24:09Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]" 396205 wikitext text/x-wiki [[ကဏ္ဍ:မဝ်ဂျူပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]] 898ebp05xa3sh5xq6nf1u3yr0fbn7jy မဝ်ဂျူ:pl-noun/testcases 828 295569 396206 2026-06-03T13:25:23Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local tests = require('Module:UnitTests') local pl_noun = require('Module:pl-noun') local m_links = require('Module:links') local inflection_mt = { __eq = function (left, right) for key, rvalue in pairs(right) do local lvalue_nl = m_links.remove_links(left[key]) local rvalue_nl = m_links.remove_links(rvalue) if (rvalue_nl ~= "*") and (lvalue_nl ~= "*") then if lvalue_nl ~= rvalue_nl then return f..." 396206 Scribunto text/plain local tests = require('Module:UnitTests') local pl_noun = require('Module:pl-noun') local m_links = require('Module:links') local inflection_mt = { __eq = function (left, right) for key, rvalue in pairs(right) do local lvalue_nl = m_links.remove_links(left[key]) local rvalue_nl = m_links.remove_links(rvalue) if (rvalue_nl ~= "*") and (lvalue_nl ~= "*") then if lvalue_nl ~= rvalue_nl then return false end end end return true end; __tostring = function (self) local casepos = { noms = 1; nomp = 2; gens = 3; genp = 4; dats = 5; datp = 6; accs = 7; accp = 8; inss = 9; insp = 10; locs = 11; locp = 12; vocs = 13; vocp = 14; } local output = {} for key, value in pairs(self) do if m_links.remove_links(value) ~= "*" then output[casepos[key]] = ('%s = "<span class="Latn mention" lang="pl">%s</span>"'):format(key, pl_noun.make_links(value, "/")) else output[casepos[key]] = ("%s = *"):format(key) end if key ~= "vocp" and mw.ustring.sub(key, -1) == "p" then output[casepos[key]] = output[casepos[key]] .. "<br />" end end return "{ " .. table.concat(output, ", ") .. " }" end; } function tests:check_autoinflect(pattern, args, lemma, expected) local argstring if args then -- The designer of Lua tables is definitely a being of pure evil. -- Their soul is as black as the darkness waiting at the end of time. local pretty_args = {} -- First output positional arguments (thos with numeric keys) for k, v in ipairs(args) do table.insert(pretty_args, v) end -- Now output keyword arguments. Do this by iterating over all -- arguments and ignoring numeric keys. for k, v in pairs(args) do if type(k) ~= "number" then table.insert(pretty_args, k .. "=" .. v) end end -- Join with commas. argstring = "|" .. table.concat(pretty_args, "|") else argstring = "" end local desc = [=[Inflection of <span class="Latn mention" lang="pl">[[%s#Polish|%s]]</span><br /><code>%s</code>]=] desc = desc:format(lemma, lemma, mw.text.nowiki("...-" .. pattern .. argstring .. "}}")) self:equals( desc, setmetatable(pl_noun.autoinflect(pattern, args or {}, lemma or ""), inflection_mt), setmetatable(expected, inflection_mt) ) end function tests:test_autoinflect_01_m_pr() self:check_autoinflect("m-pr", nil, "gazda", { noms = "gazda"; nomp = "gazdowie"; gens = "gazdy"; genp = "gazdów"; dats = "gaździe"; datp = "gazdom"; accs = "gazdę"; accp = "gazdów"; inss = "gazdą"; insp = "gazdami"; locs = "gaździe"; locp = "gazdach"; vocs = "gazdo"; vocp = "gazdowie"; }) self:check_autoinflect("m-pr", nil, "jeniec", { noms = "jeniec"; nomp = "jeńcy"; gens = "jeńca"; genp = "jeńców"; dats = "jeńcowi"; datp = "jeńcom"; accs = "jeńca"; accp = "jeńców"; inss = "jeńcem"; insp = "jeńcami"; locs = "jeńcu"; locp = "jeńcach"; vocs = "jeńcze"; vocp = "jeńcy"; }) self:check_autoinflect("m-pr", nil, "jeździec", { noms = "jeździec"; nomp = "jeźdźcy"; gens = "jeźdźca"; genp = "jeźdźców"; dats = "jeźdźcowi"; datp = "jeźdźcom"; accs = "jeźdźca"; accp = "jeźdźców"; inss = "jeźdźcem"; insp = "jeźdźcami"; locs = "jeźdźcu"; locp = "jeźdźcach"; vocs = "jeźdźcze"; vocp = "jeźdźcy"; }) self:check_autoinflect("m-pr", nil, "zawodnik", { noms = "zawodnik"; nomp = "zawodnicy"; gens = "zawodnika"; genp = "zawodników"; dats = "zawodnikowi"; datp = "zawodnikom"; accs = "zawodnika"; accp = "zawodników"; inss = "zawodnikiem"; insp = "zawodnikami"; locs = "zawodniku"; locp = "zawodnikach"; vocs = "zawodniku"; vocp = "zawodnicy"; }) self:check_autoinflect("m-pr", nil, "władca", { noms = "władca"; nomp = "władcy"; gens = "władcy"; genp = "władców"; dats = "władcy"; datp = "władcom"; accs = "władcę"; accp = "władców"; inss = "władcą"; insp = "władcami"; locs = "władcy"; locp = "władcach"; vocs = "władco"; vocp = "władcy"; }) self:check_autoinflect("m-pr", nil, "piekarz", { noms = "piekarz"; nomp = "piekarze"; gens = "piekarza"; genp = "piekarzy"; dats = "piekarzowi"; datp = "piekarzom"; accs = "piekarza"; accp = "piekarzy"; inss = "piekarzem"; insp = "piekarzami"; locs = "piekarzu"; locp = "piekarzach"; vocs = "piekarzu"; vocp = "piekarze"; }) self:check_autoinflect("m-pr", nil, "Rosjanin", { noms = "Rosjanin"; nomp = "Rosjanie"; gens = "Rosjanina"; genp = "Rosjan"; dats = "Rosjaninowi"; datp = "Rosjanom"; accs = "Rosjanina"; accp = "Rosjan"; inss = "Rosjaninem"; insp = "Rosjanami"; locs = "Rosjaninie"; locp = "Rosjanach"; vocs = "Rosjaninie"; vocp = "Rosjanie"; }) self:check_autoinflect("m-pr", nil, "księgowy", { noms = "księgowy"; nomp = "księgowi"; gens = "księgowego"; genp = "księgowych"; dats = "księgowemu"; datp = "księgowym"; accs = "księgowego"; accp = "księgowych"; inss = "księgowym"; insp = "księgowymi"; locs = "księgowym"; locp = "księgowych"; vocs = "księgowy"; vocp = "księgowi"; }) self:check_autoinflect("m-pr", nil, "łowczy", { noms = "łowczy"; nomp = "łowczy"; gens = "łowczego"; genp = "łowczych"; dats = "łowczemu"; datp = "łowczym"; accs = "łowczego"; accp = "łowczych"; inss = "łowczym"; insp = "łowczymi"; locs = "łowczym"; locp = "łowczych"; vocs = "łowczy"; vocp = "łowczy"; }) self:check_autoinflect("m-pr", nil, "Olgierd", { noms = "Olgierd"; nomp = "Olgierdzi"; gens = "Olgierda"; genp = "Olgierdów"; dats = "Olgierdowi"; datp = "Olgierdom"; accs = "Olgierda"; accp = "Olgierdów"; inss = "Olgierdem"; insp = "Olgierdami"; locs = "Olgierdzie"; locp = "Olgierdach"; vocs = "Olgierdzie"; vocp = "Olgierdzi"; }) end function tests:test_autoinflect_02_m_an() self:check_autoinflect("m-an", nil, "kurczak", { noms = "kurczak"; nomp = "kurczaki"; gens = "kurczaka"; genp = "kurczaków"; dats = "kurczakowi"; datp = "kurczakom"; accs = "kurczaka"; accp = "kurczaki"; inss = "kurczakiem"; insp = "kurczakami"; locs = "kurczaku"; locp = "kurczakach"; vocs = "kurczaku"; vocp = "kurczaki"; }) self:check_autoinflect("m-an", { dats = "kotu" }, "kot", { noms = "kot"; nomp = "koty"; gens = "kota"; genp = "kotów"; dats = "kotu"; datp = "kotom"; accs = "kota"; accp = "koty"; inss = "kotem"; insp = "kotami"; locs = "kocie"; locp = "kotach"; vocs = "kocie"; vocp = "koty"; }) self:check_autoinflect("m-an", {"bob", "r", "bóbr"}, "bóbr", { noms = "bóbr"; nomp = "bobry"; gens = "bobra"; genp = "bobrów"; dats = "bobrowi"; datp = "bobrom"; accs = "bobra"; accp = "bobry"; inss = "bobrem"; insp = "bobrami"; locs = "bobrze"; locp = "bobrach"; vocs = "bobrze"; vocp = "bobry"; }) end function tests:test_autoinflect_03_m_in() self:check_autoinflect("m-in", nil, "głos", { noms = "głos"; nomp = "głosy"; gens = "głosu"; genp = "głosów"; dats = "głosowi"; datp = "głosom"; accs = "głos"; accp = "głosy"; inss = "głosem"; insp = "głosami"; locs = "głosie"; locp = "głosach"; vocs = "głosie"; vocp = "głosy"; }) self:check_autoinflect("m-in", {"bó", "l", "u"}, "ból", { noms = "ból"; nomp = "bóle"; gens = "bólu"; genp = "bóli"; dats = "bólowi"; datp = "bólom"; accs = "ból"; accp = "bóle"; inss = "bólem"; insp = "bólami"; locs = "bólu"; locp = "bólach"; vocs = "bólu"; vocp = "bóle"; }) self:check_autoinflect("m-in", nil, "garnek", { noms = "garnek"; nomp = "garnki"; gens = "garnka"; genp = "garnków"; dats = "garnkowi"; datp = "garnkom"; accs = "garnek"; accp = "garnki"; inss = "garnkiem"; insp = "garnkami"; locs = "garnku"; locp = "garnkach"; vocs = "garnku"; vocp = "garnki"; }) self:check_autoinflect("m-in", nil, "korek", { noms = "korek"; nomp = "korki"; gens = "korka"; genp = "korków"; dats = "korkowi"; datp = "korkom"; accs = "korek"; accp = "korki"; inss = "korkiem"; insp = "korkami"; locs = "korku"; locp = "korkach"; vocs = "korku"; vocp = "korki"; }) self:check_autoinflect("m-in", nil, "szacunek", { noms = "szacunek"; nomp = "szacunki"; gens = "szacunku"; genp = "szacunków"; dats = "szacunkowi"; datp = "szacunkom"; accs = "szacunek"; accp = "szacunki"; inss = "szacunkiem"; insp = "szacunkami"; locs = "szacunku"; locp = "szacunkach"; vocs = "szacunku"; vocp = "szacunki"; }) self:check_autoinflect("m-in", {"", "", "a"}, "młot", { noms = "młot"; nomp = "młoty"; gens = "młota"; genp = "młotów"; dats = "młotowi"; datp = "młotom"; accs = "młot"; accp = "młoty"; inss = "młotem"; insp = "młotami"; locs = "młocie"; locp = "młotach"; vocs = "młocie"; vocp = "młoty"; }) self:check_autoinflect("m-in", {"", "sn", "u", "sen"}, "sen", { noms = "sen"; nomp = "sny"; gens = "snu"; genp = "snów"; dats = "snowi"; datp = "snom"; accs = "sen"; accp = "sny"; inss = "snem"; insp = "snami"; locs = "śnie"; locp = "snach"; vocs = "śnie"; vocp = "sny"; }) self:check_autoinflect("m-in", nil, "próg", { noms = "próg"; nomp = "progi"; gens = "progu"; genp = "progów"; dats = "progowi"; datp = "progom"; accs = "próg"; accp = "progi"; inss = "progiem"; insp = "progami"; locs = "progu"; locp = "progach"; vocs = "progu"; vocp = "progi"; }) self:check_autoinflect("m-in", nil, "słownik", { noms = "słownik"; nomp = "słowniki"; gens = "słownika"; genp = "słowników"; dats = "słownikowi"; datp = "słownikom"; accs = "słownik"; accp = "słowniki"; inss = "słownikiem"; insp = "słownikami"; locs = "słowniku"; locp = "słownikach"; vocs = "słowniku"; vocp = "słowniki"; }) self:check_autoinflect("m-in", nil, "półpasiec", { noms = "półpasiec"; nomp = "półpaśce"; gens = "półpaśca"; genp = "półpaśców"; dats = "półpaścowi"; datp = "półpaścom"; accs = "półpasiec"; accp = "półpaśce"; inss = "półpaścem"; insp = "półpaścami"; locs = "półpaścu"; locp = "półpaścach"; vocs = "półpaścu"; vocp = "półpaśce"; }) self:check_autoinflect("m-in", nil, "dziedziniec", { noms = "dziedziniec"; nomp = "dziedzińce"; gens = "dziedzińca"; genp = "dziedzińców"; dats = "dziedzińcowi"; datp = "dziedzińcom"; accs = "dziedziniec"; accp = "dziedzińce"; inss = "dziedzińcem"; insp = "dziedzińcami"; locs = "dziedzińcu"; locp = "dziedzińcach"; vocs = "dziedzińcu"; vocp = "dziedzińce"; }) self:check_autoinflect("m-in", nil, "mebel", { noms = "mebel"; nomp = "meble"; gens = "mebla"; genp = "mebli"; dats = "meblowi"; datp = "meblom"; accs = "mebel"; accp = "meble"; inss = "meblem"; insp = "meblami"; locs = "meblu"; locp = "meblach"; vocs = "meblu"; vocp = "meble"; }) self:check_autoinflect("m-in", nil, "węgieł", { noms = "węgieł"; nomp = "węgły"; gens = "węgła"; genp = "węgłów"; dats = "węgłowi"; datp = "węgłom"; accs = "węgieł"; accp = "węgły"; inss = "węgłem"; insp = "węgłami"; locs = "węgle"; locp = "węgłach"; vocs = "węgle"; vocp = "węgły"; }) self:check_autoinflect("m-in", nil, "węgiel", { noms = "węgiel"; nomp = "węgle"; gens = "węgla"; genp = "węgli"; dats = "węglowi"; datp = "węglom"; accs = "węgiel"; accp = "węgle"; inss = "węglem"; insp = "węglami"; locs = "węglu"; locp = "węglach"; vocs = "węglu"; vocp = "węgle"; }) self:check_autoinflect("m-in", nil, "węzeł", { noms = "węzeł"; nomp = "węzły"; gens = "węzła"; genp = "węzłów"; dats = "węzłowi"; datp = "węzłom"; accs = "węzeł"; accp = "węzły"; inss = "węzłem"; insp = "węzłami"; locs = "węźle"; locp = "węzłach"; vocs = "węźle"; vocp = "węzły"; }) self:check_autoinflect("m-in", nil, "organizm", { noms = "organizm"; nomp = "organizmy"; gens = "organizmu"; genp = "organizmów"; dats = "organizmowi"; datp = "organizmom"; accs = "organizm"; accp = "organizmy"; inss = "organizmem"; insp = "organizmami"; locs = "organizmie"; locp = "organizmach"; vocs = "organizmie"; vocp = "organizmy"; }) end function tests:test_autoinflect_04_f() self:check_autoinflect("f", nil, "bułka", { noms = "bułka"; nomp = "bułki"; gens = "bułki"; genp = "bułek"; dats = "bułce"; datp = "bułkom"; accs = "bułkę"; accp = "bułki"; inss = "bułką"; insp = "bułkami"; locs = "bułce"; locp = "bułkach"; vocs = "bułko"; vocp = "bułki"; }) self:check_autoinflect("f", nil, "galaktyka", { noms = "galaktyka"; nomp = "galaktyki"; gens = "galaktyki"; genp = "galaktyk"; dats = "galaktyce"; datp = "galaktykom"; accs = "galaktykę"; accp = "galaktyki"; inss = "galaktyką"; insp = "galaktykami"; locs = "galaktyce"; locp = "galaktykach"; vocs = "galaktyko"; vocp = "galaktyki"; }) self:check_autoinflect("f", {"kono", "pi"}, "konopia", { noms = "konopia"; nomp = "konopie"; gens = "konopi"; genp = "konopi"; dats = "konopi"; datp = "konopiom"; accs = "konopię"; accp = "konopie"; inss = "konopią"; insp = "konopiami"; locs = "konopi"; locp = "konopiach"; vocs = "konopio"; vocp = "konopie"; }) self:check_autoinflect("f", nil, "entalpia", { noms = "entalpia"; nomp = "entalpie"; gens = "entalpii"; genp = "entalpii/entalpij (archaic)"; dats = "entalpii"; datp = "entalpiom"; accs = "entalpię"; accp = "entalpie"; inss = "entalpią"; insp = "entalpiami"; locs = "entalpii"; locp = "entalpiach"; vocs = "entalpio"; vocp = "entalpie"; }) self:check_autoinflect("f", nil, "kategoria", { noms = "kategoria"; nomp = "kategorie"; gens = "kategorii"; genp = "kategorii/kategoryj (archaic)"; dats = "kategorii"; datp = "kategoriom"; accs = "kategorię"; accp = "kategorie"; inss = "kategorią"; insp = "kategoriami"; locs = "kategorii"; locp = "kategoriach"; vocs = "kategorio"; vocp = "kategorie"; }) self:check_autoinflect("f", nil, "czara", { noms = "czara"; nomp = "czary"; gens = "czary"; genp = "czar"; dats = "czarze"; datp = "czarom"; accs = "czarę"; accp = "czary"; inss = "czarą"; insp = "czarami"; locs = "czarze"; locp = "czarach"; vocs = "czaro"; vocp = "czary"; }) self:check_autoinflect("f", nil, "pryzma", { noms = "pryzma"; nomp = "pryzmy"; gens = "pryzmy"; genp = "pryzm"; dats = "pryzmie"; datp = "pryzmom"; accs = "pryzmę"; accp = "pryzmy"; inss = "pryzmą"; insp = "pryzmami"; locs = "pryzmie"; locp = "pryzmach"; vocs = "pryzmo"; vocp = "pryzmy"; }) self:check_autoinflect("f", nil, "budowla", { noms = "budowla"; nomp = "budowle"; gens = "budowli"; genp = "budowli"; dats = "budowli"; datp = "budowlom"; accs = "budowlę"; accp = "budowle"; inss = "budowlą"; insp = "budowlami"; locs = "budowli"; locp = "budowlach"; vocs = "budowlo"; vocp = "budowle"; }) self:check_autoinflect("f", nil, "żmija", { noms = "żmija"; nomp = "żmije"; gens = "żmii"; genp = "żmij"; dats = "żmii"; datp = "żmijom"; accs = "żmiję"; accp = "żmije"; inss = "żmiją"; insp = "żmijami"; locs = "żmii"; locp = "żmijach"; vocs = "żmijo"; vocp = "żmije"; }) self:check_autoinflect("f", nil, "pasja", { noms = "pasja"; nomp = "pasje"; gens = "pasji"; genp = "pasji/pasyj"; dats = "pasji"; datp = "pasjom"; accs = "pasję"; accp = "pasje"; inss = "pasją"; insp = "pasjami"; locs = "pasji"; locp = "pasjach"; vocs = "pasjo"; vocp = "pasje"; }) self:check_autoinflect("f", {"uprzę", "ż", "e", "uprząż"}, "uprząż", { noms = "uprząż"; nomp = "uprzęże"; gens = "uprzęży"; genp = "uprzęży"; dats = "uprzęży"; datp = "uprzężom"; accs = "uprząż"; accp = "uprzęże"; inss = "uprzężą"; insp = "uprzężami"; locs = "uprzęży"; locp = "uprzężach"; vocs = "uprzęży"; vocp = "uprzęże"; }) self:check_autoinflect("f", { nomp = "brwi"}, "brew", { noms = "brew"; nomp = "brwi"; gens = "brwi"; genp = "brwi"; dats = "brwi"; datp = "brwiom"; accs = "brew"; accp = "brwi"; inss = "brwią"; insp = "brwiami"; locs = "brwi"; locp = "brwiach"; vocs = "brwi"; vocp = "brwi"; }) self:check_autoinflect("f", nil, "twarz", { noms = "twarz"; nomp = "twarze"; gens = "twarzy"; genp = "twarzy"; dats = "twarzy"; datp = "twarzom"; accs = "twarz"; accp = "twarze"; inss = "twarzą"; insp = "twarzami"; locs = "twarzy"; locp = "twarzach"; vocs = "twarzy"; vocp = "twarze"; }) self:check_autoinflect("f", nil, "stal", { noms = "stal"; nomp = "stale"; gens = "stali"; genp = "stali"; dats = "stali"; datp = "stalom"; accs = "stal"; accp = "stale"; inss = "stalą"; insp = "stalami"; locs = "stali"; locp = "stalach"; vocs = "stali"; vocp = "stale"; }) self:check_autoinflect("f", nil, "nożyczki", { noms = "*"; nomp = "nożyczki"; gens = "*"; genp = "nożyczek"; dats = "*"; datp = "nożyczkom"; accs = "*"; accp = "nożyczki"; inss = "*"; insp = "nożyczkami"; locs = "*"; locp = "nożyczkach"; vocs = "*"; vocp = "nożyczki"; }) self:check_autoinflect("f", nil, "Czechy", { noms = "*"; nomp = "Czechy"; gens = "*"; genp = "Czech"; dats = "*"; datp = "Czechom"; accs = "*"; accp = "Czechy"; inss = "*"; insp = "Czechami"; locs = "*"; locp = "Czechach"; vocs = "*"; vocp = "Czechy"; }) self:check_autoinflect("f", nil, "kość", { noms = "kość"; nomp = "kości"; gens = "kości"; genp = "kości"; dats = "kości"; datp = "kościom"; accs = "kość"; accp = "kości"; inss = "kością"; insp = "kościami"; locs = "kości"; locp = "kościach"; vocs = "kości"; vocp = "kości"; }) self:check_autoinflect("f", nil, "palarnia", { noms = "palarnia"; nomp = "palarnie"; gens = "palarni"; genp = "palarni"; dats = "palarni"; datp = "palarniom"; accs = "palarnię"; accp = "palarnie"; inss = "palarnią"; insp = "palarniami"; locs = "palarni"; locp = "palarniach"; vocs = "palarnio"; vocp = "palarnie"; }) self:check_autoinflect("f", nil, "kniahini", { noms = "kniahini"; nomp = "kniahinie"; gens = "kniahini"; genp = "kniahiń"; dats = "kniahini"; datp = "kniahiniom"; accs = "kniahinię"; accp = "kniahinie"; inss = "kniahinią"; insp = "kniahiniami"; locs = "kniahini"; locp = "kniahiniach"; vocs = "kniahini"; vocp = "kniahinie"; }) self:check_autoinflect("f-adj", nil, "radna", { noms = "radna"; nomp = "radne"; gens = "radnej"; genp = "radnych"; dats = "radnej"; datp = "radnym"; accs = "radną"; accp = "radne"; inss = "radną"; insp = "radnymi"; locs = "radnej"; locp = "radnych"; vocs = "radna"; vocp = "radne"; }) self:check_autoinflect("f-adj", { vocs ="bratowo"}, "bratowa", { noms = "bratowa"; nomp = "bratowe"; gens = "bratowej"; genp = "bratowych"; dats = "bratowej"; datp = "bratowym"; accs = "bratową"; accp = "bratowe"; inss = "bratową"; insp = "bratowymi"; locs = "bratowej"; locp = "bratowych"; vocs = "bratowo"; vocp = "bratowe"; }) end function tests:test_autoinflect_05_n() self:check_autoinflect("n", nil, "jarzmo", { noms = "jarzmo"; nomp = "jarzma"; gens = "jarzma"; genp = "jarzm"; dats = "jarzmu"; datp = "jarzmom"; accs = "jarzmo"; accp = "jarzma"; inss = "jarzmem"; insp = "jarzmami"; locs = "jarzmie"; locp = "jarzmach"; vocs = "jarzmo"; vocp = "jarzma"; }) self:check_autoinflect("n", nil, "jajko", { noms = "jajko"; nomp = "jajka"; gens = "jajka"; genp = "jajek"; dats = "jajku"; datp = "jajkom"; accs = "jajko"; accp = "jajka"; inss = "jajkiem"; insp = "jajkami"; locs = "jajku"; locp = "jajkach"; vocs = "jajko"; vocp = "jajka"; }) self:check_autoinflect("n", nil, "lekarstwo", { noms = "lekarstwo"; nomp = "lekarstwa"; gens = "lekarstwa"; genp = "lekarstw"; dats = "lekarstwu"; datp = "lekarstwom"; accs = "lekarstwo"; accp = "lekarstwa"; inss = "lekarstwem"; insp = "lekarstwami"; locs = "lekarstwie"; locp = "lekarstwach"; vocs = "lekarstwo"; vocp = "lekarstwa"; }) self:check_autoinflect("n", nil, "bagno", { noms = "bagno"; nomp = "bagna"; gens = "bagna"; genp = "bagien"; dats = "bagnu"; datp = "bagnom"; accs = "bagno"; accp = "bagna"; inss = "bagnem"; insp = "bagnami"; locs = "bagnie"; locp = "bagnach"; vocs = "bagno"; vocp = "bagna"; }) self:check_autoinflect("n", nil, "szkło", { noms = "szkło"; nomp = "szkła"; gens = "szkła"; genp = "szkieł"; dats = "szkłu"; datp = "szkłom"; accs = "szkło"; accp = "szkła"; inss = "szkłem"; insp = "szkłami"; locs = "szkle"; locp = "szkłach"; vocs = "szkło"; vocp = "szkła"; }) self:check_autoinflect("n", nil, "życie", { noms = "życie"; nomp = "życia"; gens = "życia"; genp = "żyć"; dats = "życiu"; datp = "życiom"; accs = "życie"; accp = "życia"; inss = "życiem"; insp = "życiami"; locs = "życiu"; locp = "życiach"; vocs = "życie"; vocp = "życia"; }) self:check_autoinflect("n", nil, "nozdrze", { noms = "nozdrze"; nomp = "nozdrza"; gens = "nozdrza"; genp = "nozdrzy"; dats = "nozdrzu"; datp = "nozdrzom"; accs = "nozdrze"; accp = "nozdrza"; inss = "nozdrzem"; insp = "nozdrzami"; locs = "nozdrzu"; locp = "nozdrzach"; vocs = "nozdrze"; vocp = "nozdrza"; }) self:check_autoinflect("n", nil, "cielę", { noms = "cielę"; nomp = "cielęta"; gens = "cielęcia"; genp = "cieląt"; dats = "cielęciu"; datp = "cielętom"; accs = "cielę"; accp = "cielęta"; inss = "cielęciem"; insp = "cielętami"; locs = "cielęciu"; locp = "cielętach"; vocs = "cielę"; vocp = "cielęta"; }) self:check_autoinflect("n", nil, "imię", { noms = "imię"; nomp = "imiona"; gens = "imienia"; genp = "imion"; dats = "imieniu"; datp = "imionom"; accs = "imię"; accp = "imiona"; inss = "imieniem"; insp = "imionami"; locs = "imieniu"; locp = "imionach"; vocs = "imię"; vocp = "imiona"; }) self:check_autoinflect("n", nil, "obserwatorium", { noms = "obserwatorium"; nomp = "obserwatoria"; gens = "obserwatorium"; genp = "obserwatoriów"; dats = "obserwatorium"; datp = "obserwatoriom"; accs = "obserwatorium"; accp = "obserwatoria"; inss = "obserwatorium"; insp = "obserwatoriami"; locs = "obserwatorium"; locp = "obserwatoriach"; vocs = "obserwatorium"; vocp = "obserwatoria"; }) self:check_autoinflect("n-adj", nil, "młode", { noms = "młode"; nomp = "młode"; gens = "młodego"; genp = "młodych"; dats = "młodemu"; datp = "młodym"; accs = "młode"; accp = "młode"; inss = "młodym"; insp = "młodymi"; locs = "młodym"; locp = "młodych"; vocs = "młode"; vocp = "młode"; }) -- to simplify adding new tests local x = [=[ self:check_autoinflect("n", nil, "słowo", { noms = ""; nomp = ""; gens = ""; genp = ""; dats = ""; datp = ""; accs = ""; accp = ""; inss = ""; insp = ""; locs = ""; locp = ""; vocs = ""; vocp = ""; }) ]=] end return tests sxmw9u4k4l68kybedzuilzypy285hqu မဝ်ဂျူ:pl-noun/testcases/doc 828 295570 396207 2026-06-03T13:26:05Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:pl-noun/testcases|run_tests}} <includeonly> {{module cat|pl}} </includeonly>" 396207 wikitext text/x-wiki {{#invoke:pl-noun/testcases|run_tests}} <includeonly> {{module cat|pl}} </includeonly> 7zx4jdhji5j00cqvqa92x1uhp8w124u မဝ်ဂျူ:pl-adj 828 295571 396208 2026-06-03T13:39:54Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local gender = require('Module:gender and number') local m_links = require('Module:links') local lang = require("Module:languages").getByCode("pl") local export = {} -- automatic declension local inflectors = {} inflectors["^((.+)([kg]))[ia]e?$"] = function (pargs, stem, substem, extra) local ending = { ["k"] = "cy"; ["g"] = "dzy"; } return { stem .. "i", stem .. "a", stem .. "ie", substem .. ending[ext..." 396208 Scribunto text/plain local gender = require('Module:gender and number') local m_links = require('Module:links') local lang = require("Module:languages").getByCode("pl") local export = {} -- automatic declension local inflectors = {} inflectors["^((.+)([kg]))[ia]e?$"] = function (pargs, stem, substem, extra) local ending = { ["k"] = "cy"; ["g"] = "dzy"; } return { stem .. "i", stem .. "a", stem .. "ie", substem .. ending[extra], stem .. "ie", stem .. "iego", stem .. "iej", stem .. "ich", stem .. "iemu", stem .. "im", stem .. "ą", stem .. "im", stem .. "imi", (pargs.olddat and (stem .. "u") or nil) } end inflectors["^((.*)[mnpbfwszi%-]i)[ae]?$"] = function (pargs, stem, substem) return { stem, stem .. "a", stem .. "e", stem, stem .. "e", stem .. "ego", stem .. "ej", stem .. "ch", stem .. "emu", stem .. "m", stem .. "ą", stem .. "m", stem .. "mi" } end inflectors["^((.+)l)[iae]$"] = function (pargs, stem, substem) return { stem .. "i", stem .. "a", stem .. "e", stem .. "i", stem .. "e", stem .. "ego", stem .. "ej", stem .. "ich", stem .. "emu", stem .. "im", stem .. "ą", stem .. "im", stem .. "imi" } end inflectors["^(.+c)i[ae]?$"] = function (pargs, stem, substem) return { stem .. "i", stem .. "ia", stem .. "ie", stem .. "i", stem .. "ie", stem .. "iego", stem .. "iej", stem .. "ich", stem .. "iemu", stem .. "im", stem .. "ią", stem .. "im", stem .. "imi" } end inflectors["^((.+)([os])n)[yae]$"] = function (pargs, stem, substem, extra) local mpl_suffix if stem:match("zielon$") or stem:match("czerwon$") or stem:match("słon$") then -- probably the only exceptions mpl_suffix = "oni" else mpl_suffix = ({ ["o"] = "eni", ["s"] = "śni", ["z"] = "źni" })[extra] end return { stem .. "y", stem .. "a", stem .. "e", substem .. mpl_suffix, stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi", } end inflectors["^((.+[^crs])(z)n)[yae]$"] = inflectors["^((.+)([os])n)[yae]$"] -- .* instead of .+ due to [[cny]] (why are we using .+ in general anyway?) inflectors["^(.*[^osz]n)[yae]$"] = function (pargs, stem, substem, extra) return { stem .. "y", stem .. "a", stem .. "e", stem .. "i", stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi" } end inflectors["^(.+[crs]zn)[yae]$"] = inflectors["^(.*[^osz]n)[yae]$"] inflectors["^(.+[wmpb])[yae]$"] = function (pargs, stem, substem) return { stem .. "y", stem .. "a", stem .. "e", stem .. "i", stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi" } end inflectors["^((.+s)z?)[yae]$"] = function (pargs, stem, substem) return { stem .. "y", stem .. "a", stem .. "e", substem .. "i", stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi" } end inflectors["^(.+[^fwtdmrłnizshpb])[yae]$"] = function (pargs, stem, substem) return { stem .. "y", stem .. "a", stem .. "e", stem .. "y", stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi" } end inflectors["^(.+[cdr]z)[yae]$"] = inflectors["^(.+[^fwtdmrłnizshpb])[yae]$"] inflectors["^((.+)([dr]))[yae]$"] = function (pargs, stem, substem, extra) local soft_mpl_cons = { ["ch"] = "si", ["h"] = "si", ["zł"] = "źli", ["sł"] = "śli", ["ł"] = "li", ["r"] = "rzy", ["t"] = "ci", ["st"] = "ści", ["d"] = "dzi" } return { stem .. "y", stem .. "a", stem .. "e", substem .. soft_mpl_cons[extra], stem .. "e", stem .. "ego", stem .. "ej", stem .. "ych", stem .. "emu", stem .. "ym", stem .. "ą", stem .. "ym", stem .. "ymi", (pargs.olddat and (stem .. "u") or nil) } end inflectors["^((.-)(c?h))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*[^s])(zł))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*)(sł))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*[^sz])(ł))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*sz)(ł))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*)(st))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] inflectors["^((.*[^s])(t))[yae]$"] = inflectors["^((.+)([dr]))[yae]$"] -- archaic forms inflectors["^(.+[^i])en$"] = function (pargs, stem, substem, extra) return { stem .. "en", stem .. "na", stem .. "ne", stem .. "ni", stem .. "ne", stem .. "nego", stem .. "nej", stem .. "nych", stem .. "nemu", stem .. "nym", stem .. "ną", stem .. "nym", stem .. "nymi" } end inflectors["^(.+)on$"] = function (pargs, stem, substem, extra) return { stem .. "on", stem .. "ona", stem .. "one", stem .. "eni", stem .. "one", stem .. "onego", stem .. "onej", stem .. "onych", stem .. "onemu", stem .. "onym", stem .. "oną", stem .. "onym", stem .. "onymi" } end -- jakikolwiek, którykolwiek inflectors["^(.+)kolwiek$"] = function (pargs, stem) local result = export.autoinflect(stem, pargs) if result then for i, item in ipairs(result) do result[i] = item .. "kolwiek" end return result end end function export.autoinflect(lemma, pargs) pargs = pargs or {} for pat, inflector in pairs(inflectors) do local st, en, stem, substem, extra = mw.ustring.find(lemma, pat) if st then return inflector(pargs, stem, substem, extra) end end end -- automatic comparatives local comparators = {} local function bardziej(pargs, stem) return "[[bardziej]] " .. stem, "[[najbardziej]] " .. stem end comparators["^(.*ow[yaei])$"] = bardziej comparators["^(.*sk[ia]e?)$"] = bardziej comparators["^(.*scy)$"] = bardziej comparators["^(.*[^aeiou][wz]i[ae]?)$"] = bardziej comparators["^(.*[^aeiou]l[iae]?)$"] = bardziej -- -ały, -ała, -ałe (singular) comparators["^(.-)(i?a)ł([aye])$"] = function (pargs, stem, vowl, suf) local shift = { ["ia"] = "ie", ["a"] = "a" } return stem .. shift[vowl] .. "lsz" .. suf, "naj" .. stem .. shift[vowl] .. "lsz" .. suf end -- -ali (virile plural) comparators["^(.-)(i?a)li$"] = function (pargs, stem, vowl, suf) local shift = { ["ia"] = "ie", ["a"] = "a" } return stem .. shift[vowl] .. "lsi", "naj" .. stem .. shift[vowl] .. "lsi" end function export.autocompare(lemma, pargs) for pat, comparator in pairs(comparators) do local st, en, stem, substem, suf = mw.ustring.find(lemma, pat) if st then return comparator(pargs, stem, substem, suf) end end end -- template functions local function make_table(items, title, curtitle, width) local itemlinks = {} local forms = { "m|nom//voc|s|;|m|ina|acc|s", "f|nom//voc|s", "n|nom//voc//acc|s", "vr|nom//voc|p", "nv|nom//voc//acc|p", "m//n|gen|s|;|m|pers//an|acc|s", "f|gen//dat//loc|s", "gen//loc|p|;|vr|acc|p", "m//n|dat|s", "dat|p", "f|acc//ins|s", "m//n|ins//loc|s", "ins|p", "dat|arch", } local maxl = 0 for i, item in ipairs(items) do table.insert(itemlinks, item and m_links.full_link({lang = lang, term = item, accel = {form = forms[i]}})) if not width then -- speed local l = mw.ustring.len(m_links.remove_links(item)) if maxl < l then maxl = l end end end if not width then width = math.floor(maxl * 0.78) -- number obtained by anecdotal evidence width = (width < 10) and 10 or width width = 11 + (width * 5) end return ([=[<div class="NavFrame" style="display: block; width: %uem;"> <div class="NavHead" style="background:var(--wikt-palette-lighterblue)">%s</div> <div class="NavContent"> {| class="inflection-table" border="1" style="background:var(--wikt-palette-white); text-align:center; width: %uem; margin: 0; border-collapse: collapse; border-color: var(--wikt-palette-grey-7,#a2a9b1);" ! rowspan="2" style="width: 11em;" title="przypadek"style="background:var(--wikt-palette-lightblue);" | ကိစ္စ ! colspan="4" scope="colgroup" title="liczba pojedyncza" style="background:var(--wikt-palette-lightblue);" | ကိုန်ဨကဝုစ် ! colspan="3" scope="colgroup" title="liczba mnoga"style="background:var(--wikt-palette-lightblue);" | ကိုန်ဗဟုဝစ် |- ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj męskoosobowy/męskozwierzęcy" | ပူဂဵုပုလ္လိၚ်/လမျီုလုပ်ကၠုၚ် ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj męskorzeczowy" | ပုလ္လိၚ်မသက္ကုဟၟဲကဵုလမျီု ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj nijaki" | နပုလ္လိၚ် ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj żeński" | ဣတ္တိလိၚ် ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj męskoosobowy" | မဍိုက်ပေၚ်ကဵုလက်သန်လိၚ်တြုံ ! style="background:var(--wikt-palette-lightblue); min-width: 8em;" scope="col" title="rodzaj niemęskoosobowy" | မဍိုက်ပေၚ်ကဵုလက်သန်လိၚ်တြုံဟွံသေၚ် |- ! style="background:var(--wikt-palette-lighterblue);" title="mianownik (jaki? jaka? jakie?), wołacz (o!)" scope="row" | မဒုၚ်ယၟု၊ ပရေၚ်ဂယိုၚ်လမျီု | colspan="2" | %s | %s | %s | %s | %s |- ! style="background:var(--wikt-palette-lighterblue);" title="dopełniacz (jakiego? jakiej?)" scope="row" | ဗဳဇဂကူ | colspan="3" | %s | rowspan="2" | %s | colspan="2" | %s |- ! style="background:var(--wikt-palette-lighterblue);" title="celownik (jakiemu? jakiej?)" scope="row" | ပြကမ္မကာရက | colspan="3" | %s | colspan="2" | %s |- ! style="background:var(--wikt-palette-lighterblue);" title="biernik (jakiego? jaki? jaką? jakie?)" scope="row" | ကမ္မကာရက | %s | %s | %s | rowspan="2" | %s | %s | %s |- ! style="background:var(--wikt-palette-lighterblue);" title="narzędnik (jakim? jaką?)" scope="row" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက် | colspan="3" rowspan="2" | %s | colspan="2" | %s |- ! style="background:var(--wikt-palette-lighterblue);" title="miejscownik (jakim? jakiej?)" scope="row" | ခၞံဗဒှ်ဌာန်မတန်တဴ | %s | colspan="2" | %s%s |} </div> </div>]=]):format( width, title, width, itemlinks[1], itemlinks[3], itemlinks[2], itemlinks[4], itemlinks[5], itemlinks[6], itemlinks[7], itemlinks[8], itemlinks[9], itemlinks[10], itemlinks[6], itemlinks[1], itemlinks[3], itemlinks[11], itemlinks[8], itemlinks[5], itemlinks[12], itemlinks[13], itemlinks[7], itemlinks[8], itemlinks[14] and ([=[ |- ! style="background-color:var(--wikt-palette-lighterblue);" title="stary celownik (po jakiemu?)" scope="row" | old dative | lang="pl" xml:lang="pl" | %s ]=]):format(itemlinks[14]) or "" ) end function export.template_decl(frame) local pagename = mw.loadData("Module:headword/data").pagename local pargs = frame:getParent().args local demo = mw.title.getCurrentTitle().fullText == frame:getParent():getTitle() return make_table({ pargs[ 1] or "{{{1}}}", pargs[ 2] or "{{{2}}}", pargs[ 3] or "{{{3}}}", pargs[ 4] or "{{{4}}}", pargs[ 5] or "{{{5}}}", pargs[ 6] or "{{{6}}}", pargs[ 7] or "{{{7}}}", pargs[ 8] or "{{{8}}}", pargs[ 9] or "{{{9}}}", pargs[10] or "{{{10}}}", pargs[11] or "{{{11}}}", pargs[12] or "{{{12}}}", pargs[13] or "{{{13}}}", pargs[14] or demo and "{{{14}}}", }, pargs.title or ('မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <i class="Latn mention" lang="pl" xml:lang="pl">%s</i>'):format(pargs.head or parts[1] or demo and "{{{1}}}" or pagename), pagename) end function export.template_decl_y(frame) local pagename = mw.loadData("Module:headword/data").pagename local pargs = frame:getParent().args local demo = mw.title.getCurrentTitle().fullText == frame:getParent():getTitle() local lemma = pargs[1] and pargs[1] .. "y" or demo and "darmowy" or pagename if pargs[2] then if declinfo[4] ~= pargs[2] then cat = " " end declinfo[4] = pargs[2] end if mw.isSubsting() then return ("{{pl-decl-adj}}"):format( declinfo[1], declinfo[2], declinfo[3], declinfo[4], declinfo[5], declinfo[6], declinfo[7], declinfo[8], declinfo[9], declinfo[10], declinfo[11], declinfo[12], declinfo[13], declinfo[14] and (("|%s"):format(declinfo[14])) or "" ) else local table_title = pargs.title or lemma and ('မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <i class="Latn mention" lang="pl" xml:lang="pl">%s</i>'):format(lemma) or "declension table" return make_table(declinfo, table_title, pagename) .. cat end end function export.template_decl_auto(frame) local pagename = mw.loadData("Module:headword/data").pagename local pargs = frame:getParent().args local demo = mw.title.getCurrentTitle().fullText == frame:getParent():getTitle() local lemma = frame.args[1] or pargs[1]; if lemma == "" then lemma = nil end local nom_m_sg = pargs["nom_m_sg"]; if nom_m_sg == "" then nom_m_sg = nil end local nom_vr_pl = pargs["nom_vr_pl"]; if nom_vr_pl == "" then nom_vr_pl = nil end lemma = lemma or demo and "-ni" or pagename local declinfo if demo then declinfo = { "[[-ski]], [[-ty]]", "[[-ska]], [[-ta]]", "[[-skie]], [[-te]]", "[[-scy]], [[-ci]]", "[[-skie]], [[-te]]", "[[-skiego]], [[-tego]]", "[[-skiej]], [[-tej]]", "[[-skich]], [[-tych]]", "[[-skiemu]], [[-temu]]", "[[-skim]], [[-tym]]", "[[-ską]], [[-tą]]", "[[-skim]], [[-tym]]", "[[-skimi]], [[-tymi]]", "[[-sku]], [[-tu]]" } else declinfo = export.autoinflect(lemma, pargs) or error(("No declension pattern matches '%s'"):format(lemma)) if not (pargs.olddat and pargs.olddat ~= "") then declinfo[14] = nil end if nom_m_sg then -- support short adjectives declinfo[1] = nom_m_sg end if nom_vr_pl then -- support [[wesół]] declinfo[4] = nom_vr_pl end end if mw.isSubsting() then return ("{{pl-decl-adj}}"):format( declinfo[1], declinfo[2], declinfo[3], declinfo[4], declinfo[5], declinfo[6], declinfo[7], declinfo[8], declinfo[9], declinfo[10], declinfo[11], declinfo[12], declinfo[13], declinfo[14] and (("|%s"):format(declinfo[14])) or "" ) else lemma = nom_m_sg or lemma local table_title = pargs.title or lemma and ('မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <i class="Latn mention" lang="pl" xml:lang="pl">%s</i>'):format(lemma) or "declension table" return make_table(declinfo, table_title, pagename) end end return export 722ce9xruqlicpb4sfylkh4hqxu9w4f မဝ်ဂျူ:pl-adj/doc 828 295572 396209 2026-06-03T13:41:12Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module implements {{temp|pl-decl-adj}} and {{temp|pl-decl-adj-auto}}. See also: [[Module:pl-adj/testcases]]. <includeonly> {{module cat|pl}} </includeonly>" 396209 wikitext text/x-wiki This module implements {{temp|pl-decl-adj}} and {{temp|pl-decl-adj-auto}}. See also: [[Module:pl-adj/testcases]]. <includeonly> {{module cat|pl}} </includeonly> amqtid0o6d11q8ahmltaqenxmc6upb4 မဝ်ဂျူ:pl-adj/testcases 828 295573 396210 2026-06-03T13:41:44Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local tests = require('Module:UnitTests') local pl_adj = require('Module:pl-adj') local inflection_mt = { __eq = function (left, right) for key, rvalue in ipairs(right) do local lvalue = left[key] if lvalue ~= rvalue then return false end end return true end; __tostring = function (self) local output = {} for i, value in ipairs(self) do output[#output + 1] = ('"<span class="Latn mentio..." 396210 Scribunto text/plain local tests = require('Module:UnitTests') local pl_adj = require('Module:pl-adj') local inflection_mt = { __eq = function (left, right) for key, rvalue in ipairs(right) do local lvalue = left[key] if lvalue ~= rvalue then return false end end return true end; __tostring = function (self) local output = {} for i, value in ipairs(self) do output[#output + 1] = ('"<span class="Latn mention" lang="pl">[[%s#Polish|%s]]</span>"'):format(value, value) end return "{ " .. table.concat(output, ", ") .. " }" end; } function tests:check_autoinflect(lemma, expected, options) self:equals( ([=[Inflection of <span class="Latn mention" lang="pl">[[%s#Polish|%s]]</span>]=]):format(lemma, lemma), setmetatable(pl_adj.autoinflect(lemma, options or {}), inflection_mt), setmetatable(expected, inflection_mt) ) end function tests:test_autoinflector() self:check_autoinflect("krótki", { "krótki", "krótka", "krótkie", "krótcy", "krótkie", "krótkiego", "krótkiej", "krótkich", "krótkiemu", "krótkim", "krótką", "krótkim", "krótkimi" }) self:check_autoinflect("drogie", { "drogi", "droga", "drogie", "drodzy", "drogie", "drogiego", "drogiej", "drogich", "drogiemu", "drogim", "drogą", "drogim", "drogimi" }) self:check_autoinflect("obca", { "obcy", "obca", "obce", "obcy", "obce", "obcego", "obcej", "obcych", "obcemu", "obcym", "obcą", "obcym", "obcymi" }) self:check_autoinflect("kolorowe", { "kolorowy", "kolorowa", "kolorowe", "kolorowi", "kolorowe", "kolorowego", "kolorowej", "kolorowych", "kolorowemu", "kolorowym", "kolorową", "kolorowym", "kolorowymi" }) self:check_autoinflect("żaden", { "żaden", "żadna", "żadne", "żadni", "żadne", "żadnego", "żadnej", "żadnych", "żadnemu", "żadnym", "żadną", "żadnym", "żadnymi" }) self:check_autoinflect("pluszaty", { "pluszaty", "pluszata", "pluszate", "pluszaci", "pluszate", "pluszatego", "pluszatej", "pluszatych", "pluszatemu", "pluszatym", "pluszatą", "pluszatym", "pluszatymi" }) self:check_autoinflect("parna", { "parny", "parna", "parne", "parni", "parne", "parnego", "parnej", "parnych", "parnemu", "parnym", "parną", "parnym", "parnymi" }) self:check_autoinflect("większe", { "większy", "większa", "większe", "więksi", "większe", "większego", "większej", "większych", "większemu", "większym", "większą", "większym", "większymi" }) self:check_autoinflect("zajęczy", { "zajęczy", "zajęcza", "zajęcze", "zajęczy", "zajęcze", "zajęczego", "zajęczej", "zajęczych", "zajęczemu", "zajęczym", "zajęczą", "zajęczym", "zajęczymi" }) self:check_autoinflect("biegnące", { "biegnący", "biegnąca", "biegnące", "biegnący", "biegnące", "biegnącego", "biegnącej", "biegnących", "biegnącemu", "biegnącym", "biegnącą", "biegnącym", "biegnącymi" }) self:check_autoinflect("twardy", { "twardy", "twarda", "twarde", "twardzi", "twarde", "twardego", "twardej", "twardych", "twardemu", "twardym", "twardą", "twardym", "twardymi" }) self:check_autoinflect("szczęśliwe", { "szczęśliwy", "szczęśliwa", "szczęśliwe", "szczęśliwi", "szczęśliwe", "szczęśliwego", "szczęśliwej", "szczęśliwych", "szczęśliwemu", "szczęśliwym", "szczęśliwą", "szczęśliwym", "szczęśliwymi" }) self:check_autoinflect("trzecia", { "trzeci", "trzecia", "trzecie", "trzeci", "trzecie", "trzeciego", "trzeciej", "trzecich", "trzeciemu", "trzecim", "trzecią", "trzecim", "trzecimi" }) self:check_autoinflect("świeże", { "świeży", "świeża", "świeże", "świeży", "świeże", "świeżego", "świeżej", "świeżych", "świeżemu", "świeżym", "świeżą", "świeżym", "świeżymi" }) self:check_autoinflect("rączy", { "rączy", "rącza", "rącze", "rączy", "rącze", "rączego", "rączej", "rączych", "rączemu", "rączym", "rączą", "rączym", "rączymi" }) self:check_autoinflect("stare", { "stary", "stara", "stare", "starzy", "stare", "starego", "starej", "starych", "staremu", "starym", "starą", "starym", "starymi" }) self:check_autoinflect("rychła", { "rychły", "rychła", "rychłe", "rychli", "rychłe", "rychłego", "rychłej", "rychłych", "rychłemu", "rychłym", "rychłą", "rychłym", "rychłymi" }) self:check_autoinflect("mądre", { "mądry", "mądra", "mądre", "mądrzy", "mądre", "mądrego", "mądrej", "mądrych", "mądremu", "mądrym", "mądrą", "mądrym", "mądrymi" }) self:check_autoinflect("urocza", { "uroczy", "urocza", "urocze", "uroczy", "urocze", "uroczego", "uroczej", "uroczych", "uroczemu", "uroczym", "uroczą", "uroczym", "uroczymi" }) self:check_autoinflect("roztargniony", { "roztargniony", "roztargniona", "roztargnione", "roztargnieni", "roztargnione", "roztargnionego", "roztargnionej", "roztargnionych", "roztargnionemu", "roztargnionym", "roztargnioną", "roztargnionym", "roztargnionymi" }) self:check_autoinflect("jednoczesne", { "jednoczesny", "jednoczesna", "jednoczesne", "jednocześni", "jednoczesne", "jednoczesnego", "jednoczesnej", "jednoczesnych", "jednoczesnemu", "jednoczesnym", "jednoczesną", "jednoczesnym", "jednoczesnymi" }) self:check_autoinflect("przyjazna", { "przyjazny", "przyjazna", "przyjazne", "przyjaźni", "przyjazne", "przyjaznego", "przyjaznej", "przyjaznych", "przyjaznemu", "przyjaznym", "przyjazną", "przyjaznym", "przyjaznymi" }) self:check_autoinflect("autentyczny", { "autentyczny", "autentyczna", "autentyczne", "autentyczni", "autentyczne", "autentycznego", "autentycznej", "autentycznych", "autentycznemu", "autentycznym", "autentyczną", "autentycznym", "autentycznymi" }) self:check_autoinflect("zewnętrzne", { "zewnętrzny", "zewnętrzna", "zewnętrzne", "zewnętrzni", "zewnętrzne", "zewnętrznego", "zewnętrznej", "zewnętrznych", "zewnętrznemu", "zewnętrznym", "zewnętrzną", "zewnętrznym", "zewnętrznymi" }) self:check_autoinflect("cudzy", { "cudzy", "cudza", "cudze", "cudzy", "cudze", "cudzego", "cudzej", "cudzych", "cudzemu", "cudzym", "cudzą", "cudzym", "cudzymi" }) self:check_autoinflect("starsze", { "starszy", "starsza", "starsze", "starsi", "starsze", "starszego", "starszej", "starszych", "starszemu", "starszym", "starszą", "starszym", "starszymi" }) end return tests azcc5oewdvjq3vzrp00hs5ijbnmzmph မဝ်ဂျူ:pl-adj/testcases/doc 828 295574 396211 2026-06-03T13:42:25Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:pl-adj/testcases|run_tests}} <includeonly> {{module cat|pl}} </includeonly>" 396211 wikitext text/x-wiki {{#invoke:pl-adj/testcases|run_tests}} <includeonly> {{module cat|pl}} </includeonly> dejgud0vbhpec3whk45x13rdxzpvp4o ထာမ်ပလိက်:pl-decl-noun-m-in/documentation 10 295575 396213 2026-06-03T13:48:41Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> This declension table is for Polish <u>masculine inanimate</u> nouns. If the parameters are omitted, it will guess the correct place to split the word into the stem and ending, and will handle some common vowel elisions (e.g. -iec, -ek). The lemma is taken from the page title, but this can be overridden with the paramet..." 396213 wikitext text/x-wiki {{documentation subpage}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> This declension table is for Polish <u>masculine inanimate</u> nouns. If the parameters are omitted, it will guess the correct place to split the word into the stem and ending, and will handle some common vowel elisions (e.g. -iec, -ek). The lemma is taken from the page title, but this can be overridden with the parameter {{para|lemma}}. ===Usage=== <tt><nowiki>====Declension====</nowiki></tt><br> <tt><nowiki>{{pl-decl-noun-m-in|||}}</nowiki></tt> All parameters are optional. * First parameter: '''word stem''' in genitive singular form. * Second parameter: '''last consonant or cluster''' in genitive singular form. * Third parameter: '''genitive singular ending''' ** Note that the first three parameters essentially split the genitive singular into three parts. ** Use more than one consonant if the resulting cluster has palatalization in the locative singular; this includes sł, sm, sn, st, zd, zł, zm, zn. ** Soft consonants in their i-form have to be treated as a cluster: bi, ci, dzi, ni, pi, si, wi, zi. **For word stems that differ between the nominative singular and other forms of the word, the latter form of the stem is to be used here (see '''fourth parameter''' below). * Fourth parameter: '''nominative singular form''', useful for words where the stem differs between the nominative singular and other forms (e.g. stół/stoł-, dąb/dęb-, latawiec/latawc-) * Fifth parameter: '''alternate form of the genitive plural''' ===Examples=== * dąb: {{temp|pl-decl-noun-m-in|dę|b|u|dąb}} * balast: {{temp|pl-decl-noun-m-in|bala|st|u}} * wypadek: {{temp|pl-decl-noun-m-in|wypad|k|u|wypadek}} * piec: {{temp|pl-decl-noun-m-in|pie|c|a}} <includeonly> <!-- CATEGORIES AND INTERWIKIS HERE, THANKS --> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ပဝ်လာန်ဂမၠိုၚ်|masc-inani]] </includeonly> r9bcrti4qouy6c930k2vhxq2caqmag6 ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ပဝ်လာန်ဂမၠိုၚ် 14 295576 396214 2026-06-03T13:50:16Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]" 396214 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]] fhb1gvh9ykls4foyqkux65ujk78inyz ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏပဝ်လာန်ဂမၠိုၚ် 14 295577 396215 2026-06-03T13:51:59Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]" 396215 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]] g87nrl67z802fhu5wavd3av6dk07aro ကဏ္ဍ:ကာရန်:ပဝ်လာန်/ɛrjaw 14 295578 396219 2026-06-03T14:19:15Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » :ကဏ္ဍ:ကာ..." 396219 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -ɛrjaw :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် ɛrjaw ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ɛrjaw]] 25cwlt5kgrxy64phw5zxmdwnzyvp1ww materiôł 0 295579 396220 2026-06-03T14:21:18Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ကသှုဗဳယာန်== ===နာမ်=== {{head|csb|နာမ်}} # ကပေါတ်ကညောတ်။" 396220 wikitext text/x-wiki ==ကသှုဗဳယာန်== ===နာမ်=== {{head|csb|နာမ်}} # ကပေါတ်ကညောတ်။ shgq8wjys0k2icuukjzlz7cc3ohy31h materialik 0 295580 396221 2026-06-03T14:22:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်လာန်== ===နာမ်=== {{head|pl|ဗီုပြၚ်နာမ်|g=f}} # {{plural of|pl|materiał}}" 396221 wikitext text/x-wiki ==ပဝ်လာန်== ===နာမ်=== {{head|pl|ဗီုပြၚ်နာမ်|g=f}} # {{plural of|pl|materiał}} j2fh4657jq1lfob8lmjrjy0ka090pry materiałowy 0 295581 396222 2026-06-03T14:22:40Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်လာန်== ===နာမ်=== {{head|pl|ဗီုပြၚ်နာမ်|g=f}} # {{plural of|pl|materiał}}" 396222 wikitext text/x-wiki ==ပဝ်လာန်== ===နာမ်=== {{head|pl|ဗီုပြၚ်နာမ်|g=f}} # {{plural of|pl|materiał}} j2fh4657jq1lfob8lmjrjy0ka090pry mat. 0 295582 396223 2026-06-03T14:25:24Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|Appendix:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "mat"}} =={{=en=}}== ===နာမ်=== {{en-noun|-}} # {{abbreviation of|en|maternity}}. ===ဝေါဟာလွာ=== * {{anagrams|en|a=amt|AMT|ATM|MTA|TAM|TMA|amt|amt.|atm|tam}} ==သွဳဒေန်== ===နာမ်=== {{head|sv|noun}} # {{abbreviation of|sv|matematik}}" 396223 wikitext text/x-wiki {{also|Appendix:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "mat"}} =={{=en=}}== ===နာမ်=== {{en-noun|-}} # {{abbreviation of|en|maternity}}. ===ဝေါဟာလွာ=== * {{anagrams|en|a=amt|AMT|ATM|MTA|TAM|TMA|amt|amt.|atm|tam}} ==သွဳဒေန်== ===နာမ်=== {{head|sv|noun}} # {{abbreviation of|sv|matematik}} 9ky8h83oi4g5v59mkdf1lwe0d95ubbc အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "mat" 100 295583 396224 2026-06-03T14:33:34Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "ဝေါဟာ “mat” ဝွံ မပြာကတ်ကၠုၚ်ပ္ဍဲအရေဝ်ဘာသာဗွဲမဂၠိုၚ်၊ မနွံမဂၠိုၚ်ကဵုဗီုပြၚ်နာနာသာ်နကဵုမရပ်စပ်သုၚ်စောဲမဆေၚ်စပ်ကဵု ပွမသုၚ်စောဲမအခဝ်ဇၞော်၊ သၚ်္ကေတမထပိ..." 396224 wikitext text/x-wiki ဝေါဟာ “mat” ဝွံ မပြာကတ်ကၠုၚ်ပ္ဍဲအရေဝ်ဘာသာဗွဲမဂၠိုၚ်၊ မနွံမဂၠိုၚ်ကဵုဗီုပြၚ်နာနာသာ်နကဵုမရပ်စပ်သုၚ်စောဲမဆေၚ်စပ်ကဵု ပွမသုၚ်စောဲမအခဝ်ဇၞော်၊ သၚ်္ကေတမထပိုတ်ကုတ်ဝါကျ ကဵု ပ္ဍဲအက္ခရ်တၞဟ်ဂမၠိုၚ်။ {{wp|mat|lang=en}} ==ပွမသုၚ်စောဲမလိက်ဇၞော်ဍောတ်ကဵုလက္ခဏပ္တိတ်ရမျာၚ်== {{top2}} *[[mat]] *[[Mat]] *[[mAt]] *[[MAT]] *[[mat.]] *[[Mat.]] *[[mat']] *[[m'at]] *[[mat-]] *[[-mat]] {{bottom}} ==လက္ခဏပတပ်ဗၠိုဟ်ရမျာၚ်== {{top3}} *[[mať]] *[[maț]] *[[mát]] *[[máť]] *[[mɑ̀t]] *[[måt]] *[[mạt]] *[[mät]], [[-mät]] *[[mât]] *[[mâț]] *[[mất]] *[[măt]] *[[mắt]] *[[mặt]] *[[mật]] {{bottom}} ==မၞုံသီုဂၞန်ဂမၠိုၚ်== {{top3}} *[[mat1]] *[[mat6]] *[[mat⁷]] {{bottom}} ==မအခဝ်တၞဟ်== {{top2}} ; အာမေနဳယာန် * [[մատ]] ; မန်/ဗၟာ * [[မတ်]] ; သဳရဳလိ * [[мат]], [[Мат]], [[МАТ]] * [[мать]] ; ဂျောန်ဂျဳယာန် * [[მათ]] ; ဟာန်ဂူ * [[맛]] ; သေံ * [[มัด]] * [[มัด่]] {{bottom}} ==ဗဵုရံၚ်ဏအ်ကီု== *[[အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "m"]] *[[အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "a"]] *[[အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "t"]] *[[အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "ma"]] *[[အဆက်လက္ကရဴ:ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵု "at"]] ===ဗီုပ္တိတ်ရမျာၚ်တၞဟ်ခြာ=== *[[matt]] *[[matte]] [[ကဏ္ဍ:ပွမပံၚ်စပ်ဗီုပြၚ်နာနာသာ်မဆေၚ်စပ်ကဵုမလိက်-ပိမ|mat]] 0fi45j0injfk90gljbx6r7vfncspdcf maternity 0 295584 396225 2026-06-03T14:48:01Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "=={{=en=}}== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|en|fr|maternité}}၊ နူကဵုဝေါဟာ {{uder|en|la|māternitās}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|en|/məˈtɜːnɪti/|a=RP}} * {{audio|en|LL-Q1860 (eng)-Vealhurl-maternity.wav|a=Southern England}} * {{IPA|en|/məˈtɜɹnəti/|[-ɾi]|a=GA}} * {{rhymes|en|ɜː(ɹ)nɪti|s=4}} * {{hyphenation|en|ma|tern|i|ty..." 396225 wikitext text/x-wiki =={{=en=}}== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|en|fr|maternité}}၊ နူကဵုဝေါဟာ {{uder|en|la|māternitās}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|en|/məˈtɜːnɪti/|a=RP}} * {{audio|en|LL-Q1860 (eng)-Vealhurl-maternity.wav|a=Southern England}} * {{IPA|en|/məˈtɜɹnəti/|[-ɾi]|a=GA}} * {{rhymes|en|ɜː(ɹ)nɪti|s=4}} * {{hyphenation|en|ma|tern|i|ty}} ===နာမ်=== {{en-noun|~}} # ဘဝမိ၊ နဒဒှ်မိ။ 2eutkuf2ezlnziv5ff3u7fcqy5qc4gx ကဏ္ဍ:ကာရန်:အၚ်္ဂလိက်/ɜː(ɹ)nɪti 14 295585 396226 2026-06-03T14:51:25Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာအၚ်္ဂလိက်|အၚ်္ဂလိက်]] » :ကဏ..." 396226 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာအၚ်္ဂလိက်|အၚ်္ဂလိက်]] » [[:ကဏ္ဍ:ကာရန်:အၚ်္ဂလိက်|ကာရန်ဂမၠိုၚ်]] » -ɜː(ɹ)nɪti :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာအၚ်္ဂလိက်|အၚ်္ဂလိက်]]မနွံကာရန် ɜː(ɹ)nɪti ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:အၚ်္ဂလိက်|ɜː(ɹ)nɪti ]] 3ilca4255bdsk9cqxkixxks0j4v9plq maternities 0 295586 396227 2026-06-03T14:53:04Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "=={{=en=}}== ===နာမ်=== {{head|en|noun form}} # {{plural of|en|maternity}} ===ဝေါဟာလွာ=== * {{anagrams|en|a=aeeiimnrstt|sarmientite|semitertian}}" 396227 wikitext text/x-wiki =={{=en=}}== ===နာမ်=== {{head|en|noun form}} # {{plural of|en|maternity}} ===ဝေါဟာလွာ=== * {{anagrams|en|a=aeeiimnrstt|sarmientite|semitertian}} 9536tjdngv47mvjimkyqxs8stccb482 maternitas 0 295587 396228 2026-06-03T14:55:34Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==လပ်တေန်== ===ဗွဟ်ရမ္သာၚ်=== * {{la-IPA|māternitās}} ===နာမ်=== {{la-noun|māternitās<3>}} {{tlb|la|Medieval Latin}} # {{lb|la|Medieval Latin}} ဘဝမိ။ ====လဟုတ်စှ်ေ==== {{la-ndecl|māternitās<3>}} ===မဒုၚ်လွဳစ=== * {{desc|ca|maternitat}} * {{desc|en|maternity}} * {{desc|fr|maternité}} * {{desc|gl|maternidade}} * {{desc|..." 396228 wikitext text/x-wiki ==လပ်တေန်== ===ဗွဟ်ရမ္သာၚ်=== * {{la-IPA|māternitās}} ===နာမ်=== {{la-noun|māternitās<3>}} {{tlb|la|Medieval Latin}} # {{lb|la|Medieval Latin}} ဘဝမိ။ ====လဟုတ်စှ်ေ==== {{la-ndecl|māternitās<3>}} ===မဒုၚ်လွဳစ=== * {{desc|ca|maternitat}} * {{desc|en|maternity}} * {{desc|fr|maternité}} * {{desc|gl|maternidade}} * {{desc|it|maternità}} * {{desc|pt|maternidade}} * {{desc|ro|maternitate}} * {{desc|es|maternidad}} t1v1mdi30zjlf5y25ymryss5p82x0n3 maternitatis 0 295588 396235 2026-06-03T15:56:12Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==လပ်တေန်== ===ဗွဟ်ရမ္သာၚ်=== * {{la-IPA|māternitātis}} ===နာမ်=== {{head|la|noun form|head=māternitātis}} # {{inflection of|la|māternitās||gen|s}}" 396235 wikitext text/x-wiki ==လပ်တေန်== ===ဗွဟ်ရမ္သာၚ်=== * {{la-IPA|māternitātis}} ===နာမ်=== {{head|la|noun form|head=māternitātis}} # {{inflection of|la|māternitās||gen|s}} ibsgm6vidg7jxv0ggo7yi6yfj3z9jl7 maternité 0 295589 396236 2026-06-03T16:04:19Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|matèrnité}} ==ပြၚ်သေတ်== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|fr|la|maternitas|maternitātem}}၊ နူကဵုဝေါဟာ {{m|la|māter}} ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} ===နာမ်=== {{fr-noun|f}} # ဘဝမိ၊ ပရေၚ်နဒဒှ်မိ။ # ပရေၚ်ပဋိသန္ဓိက္တဵုဒှ်မိ..." 396236 wikitext text/x-wiki {{also|matèrnité}} ==ပြၚ်သေတ်== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|fr|la|maternitas|maternitātem}}၊ နူကဵုဝေါဟာ {{m|la|māter}} ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} ===နာမ်=== {{fr-noun|f}} # ဘဝမိ၊ ပရေၚ်နဒဒှ်မိ။ # ပရေၚ်ပဋိသန္ဓိက္တဵုဒှ်မိ။ # မမၚ်မွဲစဵုဒၞာဘဝမိ။ 44zuk8ehbkskpduqav7ajkc752c0icc maternités 0 295590 396237 2026-06-03T16:06:15Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပြၚ်သေတ်== ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} ===နာမ်=== {{head|fr|noun form|g=f}} # {{plural of|fr|maternité}} ===ဝေါဟာလွာ=== * {{l|fr|tamisèrent}}, {{l|fr|terminâtes}}" 396237 wikitext text/x-wiki ==ပြၚ်သေတ်== ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} ===နာမ်=== {{head|fr|noun form|g=f}} # {{plural of|fr|maternité}} ===ဝေါဟာလွာ=== * {{l|fr|tamisèrent}}, {{l|fr|terminâtes}} o8y734ds73hcyqsviinxc06cy22swnr tamisèrent 0 295591 396238 2026-06-03T16:07:46Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပြၚ်သေတ်== ===ကြိယာ=== {{head|fr|verb form}} # {{inflection of|fr|tamiser||3|p|phis}} ===ဝေါဟာလွာ=== * {{l|fr|maternités}}, {{l|fr|terminâtes}}" 396238 wikitext text/x-wiki ==ပြၚ်သေတ်== ===ကြိယာ=== {{head|fr|verb form}} # {{inflection of|fr|tamiser||3|p|phis}} ===ဝေါဟာလွာ=== * {{l|fr|maternités}}, {{l|fr|terminâtes}} ct9qxs0dutkwjeg9fm1hlnfurcpga3l tamiser 0 295592 396239 2026-06-03T16:12:28Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပြၚ်သေတ်== ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} * {{audio|fr|Fr-tamiser.ogg}} * {{audio|fr|LL-Q150 (fra)-WikiLucas00-tamiser.wav|a=<<France>> (<<Lyon>>)}} * {{audio|fr|LL-Q150 (fra)-Jérémy-Günther-Heinz Jähnick-tamiser.wav|a=<<France>> (<<Somain>>)}} ===ကြိယာ=== {{fr-verb}} # သကဵုကၞာဲဇာ၊ သကဵုခ္ဍိုဟ် (မရပ်စပ်ဂ..." 396239 wikitext text/x-wiki ==ပြၚ်သေတ်== ===ဗွဟ်ရမ္သာၚ်=== * {{fr-IPA}} * {{audio|fr|Fr-tamiser.ogg}} * {{audio|fr|LL-Q150 (fra)-WikiLucas00-tamiser.wav|a=<<France>> (<<Lyon>>)}} * {{audio|fr|LL-Q150 (fra)-Jérémy-Günther-Heinz Jähnick-tamiser.wav|a=<<France>> (<<Somain>>)}} ===ကြိယာ=== {{fr-verb}} # သကဵုကၞာဲဇာ၊ သကဵုခ္ဍိုဟ် (မရပ်စပ်ဂဇာမွဲသာ်)။ ===ဝေါဟာလွာ=== * {{l|fr|Artémis}}, {{l|fr|maitres}}, {{l|fr|maîtres}}, {{l|fr|méritas}}, {{l|fr|mirâtes}}, {{l|fr|miteras}}, {{l|fr|remisât}}, {{l|fr|rimâtes}}, {{l|fr|tarîmes}}, {{l|fr|tirâmes}}, {{l|fr|triâmes}} 26rfhg6qe1hmwj5xb292hqmt7py9o1w matèrnité 0 295593 396240 2026-06-03T16:15:32Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|maternité}} ==နဝ်မေံ== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|nrf|la-med|māternitās}}၊ နူကဵုဝေါဟာ {{uder|nrf|la|māter}} ===နာမ်=== {{nrf-noun|f}} # ဘဝမိ။" 396240 wikitext text/x-wiki {{also|maternité}} ==နဝ်မေံ== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{uder|nrf|la-med|māternitās}}၊ နူကဵုဝေါဟာ {{uder|nrf|la|māter}} ===နာမ်=== {{nrf-noun|f}} # ဘဝမိ။ ojema0xb8bo3g02qb4qb6eogd6w6qgd matèrnités 0 295594 396241 2026-06-03T16:16:55Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==နဝ်မေံ== ===နာမ်=== {{head|nrf|ဗီုပြၚ်နာမ်}} # {{plural of|nrf|matèrnité}}" 396241 wikitext text/x-wiki ==နဝ်မေံ== ===နာမ်=== {{head|nrf|ဗီုပြၚ်နာမ်}} # {{plural of|nrf|matèrnité}} bl3ok7n1mvjkqjv8wkuj3ij2ha41rr8 matematik 0 295595 396242 2026-06-03T16:34:46Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|Matematik}} ==အလ်ဗနဳယာန်== ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|sq|[matɛmaˈtik]}} ====နာမဝိသေသန==== {{sq-adj|mp=matematikë|fp=matematike}} # မဆေၚ်စပ်ကဵုသၚ်္ချာ။ ==ခရိုၚ်မာၚ်တတာ== ===နိရုတ်=== {{bor+|crh|fr|mathématique}} ===နာမ်=== {{head|crh|noun}} # တၠပညာသ..." 396242 wikitext text/x-wiki {{also|Matematik}} ==အလ်ဗနဳယာန်== ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|sq|[matɛmaˈtik]}} ====နာမဝိသေသန==== {{sq-adj|mp=matematikë|fp=matematike}} # မဆေၚ်စပ်ကဵုသၚ်္ချာ။ ==ခရိုၚ်မာၚ်တတာ== ===နိရုတ်=== {{bor+|crh|fr|mathématique}} ===နာမ်=== {{head|crh|noun}} # တၠပညာသၚ်္ချာ။ #: {{syn|crh|riyaziyatçı}} ====လဟုတ်စှ်ေ==== {{crh-decl|e|t}} ====နာမဝိသေသန==== {{head|crh|adjective}} # မဆေၚ်စပ်ကဵုသၚ်္ချာ။ #: {{syn|crh|riyaziy}} ==ချက်ခ်== ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA|[ty]}} * {{audio|cs|LL-Q9056 (ces)-Ghost4Man-matematik.wav}} * {{rhymes|cs|atɪk|s=4}} ===နာမ်=== {{cs-noun|m-an|f=matematička|adj=matematický}} # တၠပညာသၚ်္ချာ။ ====လဟုတ်စှ်ေ==== {{cs-ndecl|m.an}} ==ဒိန်နေတ်== {{wp|da:}} ===နာမ်=== {{da-noun|matematikken|-}} # သၚ်္ချာ။ ====လဟုတ်စှ်ေ==== {{da-noun-infl|matematikken|n=sg}} ==ဟေဲယှေန် ခရေဝ်အဝ်လ်== {{wp|ht:}} ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{der|ht|fr|mathématiques}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|ht|/matematik/}} ===နာမ်=== {{head|ht|noun}} # သၚ်္ချာ။ ==မလေဝ်== {{wp|ms:}} ===ပွံၚ်နဲတၞဟ်=== * {{alt|ms|matĕmatik||pre-1972}} * {{alt|id|matematika|[[matematika|matématika]]||Indonesia}} ===နိရုတ်=== {{bor+|ms|en|mathematics}}၊ နူကဵုဝေါဟာ {{der|ms|la|mathēmatica}}၊ နကဵုအဆက်ဝေါဟာ {{der|ms|grc|μαθηματικός}} ===ဗွဟ်ရမ္သာၚ်=== * {{ms-IPA|a=Baku}} ** {{audio|ms|Ms-MY-matematik.ogg|a=Malaysia}} ** {{rhymes|ms|atik|s=4}} * {{lb|ms|Johor-Riau}} ** {{ms-IPA|mɛte.mɛtik|aa=English-based|bullets=2}} ** {{rhymes|ms|ɛtik|s=4}} <!-- Followed proper Johor-Riau rule, but is not used ** {{ms-IPA|matematék|aa=|bullets=2}} Followed proper Johor-Riau rule, but is not used --> * {{hyph|ms|ma|te|ma|tik}} ===နာမ်=== {{ms-noun|j=ماتماتيک}} # သၚ်္ချာ။ #: {{syn|ms|ilmu hisab}} #: {{syn|id|ilmu pasti}} ==သလဝ်ဝေန်နဳယျာ== ===ဗွဟ်ရမ္သာၚ်=== * {{sk-IPA|t=loan}} ===နာမ်=== {{sk-noun|m-pr}} # တၠပညာသၚ်္ချာ။ ====လဟုတ်စှ်ေ==== {{sk-ndecl|m-pr|pl=i}} ==သွဳဒေန်== {{wp|sv:}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|sv|/matɛmaˈtiːk/}} * {{rhymes|sv|iːk|s=4}} * {{audio|sv|Sv-matematik.ogg}} ===နာမ်=== {{sv-noun|c}} # သၚ်္ချာ။ #: {{syn|sv|matte|q=colloquial}} ====လဟုတ်စှ်ေ==== {{sv-noun-unc-irreg-c|2=matematiken}} ==တူရကဳ== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ{{bor|tr|fr|mathématique}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|tr|/mɑtemɑˈtic/}} * {{hyph|tr|ma|te|ma|tik}} * {{audio|tr|LL-Q256 (tur)-ToprakM-matematik.wav}} ===နာမ်=== {{tr-noun|matematiği|ler}} # သၚ်္ချာ။ #: {{syn|tr|riyaziye}} ====လဟုတ်စှ်ေ==== {{tr-infl-noun-c|i|poss=1|stem=matematiğ}} 7rtwjzqi0i0fbh0ejtgqtgv9t9poyyn 396286 396242 2026-06-04T04:57:05Z 咽頭べさ 33 396286 wikitext text/x-wiki {{also|Matematik}} ==အလ်ဗနဳယာန်== ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|sq|[matɛmaˈtik]}} ====နာမဝိသေသန==== {{sq-adj|mp=matematikë|fp=matematike}} # မဆေၚ်စပ်ကဵုသၚ်္ချာ။ ==ခရိုၚ်မာၚ်တတာ== ===နိရုတ်=== {{bor+|crh|fr|mathématique}} ===နာမ်=== {{head|crh|noun}} # တၠပညာသၚ်္ချာ။ #: {{syn|crh|riyaziyatçı}} ====လဟုတ်စှ်ေ==== {{crh-decl|e|t}} ====နာမဝိသေသန==== {{head|crh|adjective}} # မဆေၚ်စပ်ကဵုသၚ်္ချာ။ #: {{syn|crh|riyaziy}} ==ချက်ခ်== ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA|[ty]}} * {{audio|cs|LL-Q9056 (ces)-Ghost4Man-matematik.wav}} * {{rhymes|cs|atɪk|s=4}} ===နာမ်=== {{cs-noun|m-an|f=matematička|adj=matematický}} # တၠပညာသၚ်္ချာ။ ====လဟုတ်စှ်ေ==== {{cs-ndecl|m.an}} ==ဒိန်နေတ်== {{wp|da:}} ===နာမ်=== {{da-noun|matematikken|-}} # သၚ်္ချာ။ ====လဟုတ်စှ်ေ==== {{da-noun-infl|matematikken|n=sg}} ==ဟေဲယှေန် ခရေဝ်အဝ်လ်== {{wp|ht:}} ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{der|ht|fr|mathématiques}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|ht|/matematik/}} ===နာမ်=== {{head|ht|noun}} # သၚ်္ချာ။ ==မလေဝ်== {{wp|ms:}} ===ပွံၚ်နဲတၞဟ်=== * {{alt|ms|matĕmatik||pre-1972}} * {{alt|id|matematika|[[matematika|matématika]]||Indonesia}} ===နိရုတ်=== {{bor+|ms|en|mathematics}}၊ နူကဵုဝေါဟာ {{der|ms|la|mathēmatica}}၊ နကဵုအဆက်ဝေါဟာ {{der|ms|grc|μαθηματικός}} ===ဗွဟ်ရမ္သာၚ်=== * {{ms-IPA|a=Baku}} ** {{audio|ms|Ms-MY-matematik.ogg|a=Malaysia}} ** {{rhymes|ms|atik|s=4}} * {{lb|ms|Johor-Riau}} ** {{ms-IPA|mɛte.mɛtik|aa=English-based|bullets=2}} ** {{rhymes|ms|ɛtik|s=4}} <!-- Followed proper Johor-Riau rule, but is not used ** {{ms-IPA|matematék|aa=|bullets=2}} Followed proper Johor-Riau rule, but is not used --> * {{hyph|ms|ma|te|ma|tik}} ===နာမ်=== {{ms-noun|j=ماتماتيک}} # သၚ်္ချာ။ #: {{syn|ms|ilmu hisab}} #: {{syn|id|ilmu pasti}} ==သလဝ်ဝေန်နဳယျာ== ===ဗွဟ်ရမ္သာၚ်=== * {{sk-IPA|t=loan}} ===နာမ်=== {{sk-noun|m-pr}} # တၠပညာသၚ်္ချာ။ <!-- ====လဟုတ်စှ်ေ==== {{sk-ndecl|m-pr|pl=i}} --> ==သွဳဒေန်== {{wp|sv:}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|sv|/matɛmaˈtiːk/}} * {{rhymes|sv|iːk|s=4}} * {{audio|sv|Sv-matematik.ogg}} ===နာမ်=== {{sv-noun|c}} # သၚ်္ချာ။ #: {{syn|sv|matte|q=colloquial}} ====လဟုတ်စှ်ေ==== {{sv-noun-unc-irreg-c|2=matematiken}} ==တူရကဳ== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ{{bor|tr|fr|mathématique}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|tr|/mɑtemɑˈtic/}} * {{hyph|tr|ma|te|ma|tik}} * {{audio|tr|LL-Q256 (tur)-ToprakM-matematik.wav}} ===နာမ်=== {{tr-noun|matematiği|ler}} # သၚ်္ချာ။ #: {{syn|tr|riyaziye}} ====လဟုတ်စှ်ေ==== {{tr-infl-noun-c|i|poss=1|stem=matematiğ}} 7z3a3bf3j3ymxsmn22eyr4so6jdazgy ထာမ်ပလိက်:crh-decl 10 295596 396243 2026-06-03T16:38:20Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|error}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m-self|crh||{{pagename}}}}|palette=blue|tall=yes}} ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! မဒုၚ်ယၟု | {{l-self|crh|{{pagename}}}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}r|accel-form=nom{{!}}pl}} |- !..." 396243 wikitext text/x-wiki {{#invoke:checkparams|error}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m-self|crh||{{pagename}}}}|palette=blue|tall=yes}} ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! မဒုၚ်ယၟု | {{l-self|crh|{{pagename}}}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}r|accel-form=nom{{!}}pl}} |- ! ဗဳဇဂကူ | {{l-self|crh|{{pagename}}n{{crh-v2|{{{1}}}}}ñ|accel-form=gen{{!}}s}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}rn{{crh-v2|{{{1}}}}}ñ|accel-form=gen{{!}}pl}} |- ! ပြကမ္မကာရက | {{l-self|crh|{{pagename}}{{#switch:{{{2}}}|ç|f|k|p|q|s|t={{crh-k|{{{1}}}}}|{{crh-g|{{{1}}}}}}}{{crh-v1|{{{1}}}}}|accel-form=dat{{!}}s}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}r{{crh-g|{{{1}}}}}{{crh-v1|{{{1}}}}}|accel-form=dat{{!}}pl}} |- ! ကမ္မကာရက | {{l-self|crh|{{pagename}}n{{crh-v2|{{{1}}}}}|accel-form=acc{{!}}s}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}rn{{crh-v2|{{{1}}}}}|accel-form=acc{{!}}pl}} |- ! ခၞံဗဒှ်ဌာန်မတန်တဴ | {{l-self|crh|{{pagename}}{{#switch:{{{2}}}|ç|f|k|p|q|s|t=t|d}}{{crh-v1|{{{1}}}}}|accel-form=loc{{!}}s}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}rd{{crh-v1|{{{1}}}}}|accel-form=loc{{!}}pl}} |- ! ပရေၚ်မလၚ် | {{l-self|crh|{{pagename}}{{#switch:{{{2}}}|ç|f|k|p|q|s|t=t|d}}{{crh-v1|{{{1}}}}}n|accel-form=abl{{!}}s}} | {{l-self|crh|{{pagename}}l{{crh-v1|{{{1}}}}}rd{{crh-v1|{{{1}}}}}n|accel-form=abl{{!}}pl}} {{inflection-table-bottom}}<!-- --><noinclude>{{documentation}}</noinclude> drfhwd5qp0n5pw8m112fhvit3svz5y3 ထာမ်ပလိက်:crh-decl/documentation 10 295597 396244 2026-06-03T16:39:38Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. --> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်|*noun1]] </includeonly>" 396244 wikitext text/x-wiki {{documentation subpage}} {{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. --> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်|*noun1]] </includeonly> eybhdwwg612p8i5xdphe1zq5pmys87d ထာမ်ပလိက်:crh-v1 10 295598 396245 2026-06-03T16:40:48Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#switch:{{{1}}}|a|ı|o|u=a|ä|e|i|ö|ü=e}}<noinclude>{{tcat|inflsub}}</noinclude>" 396245 wikitext text/x-wiki {{#switch:{{{1}}}|a|ı|o|u=a|ä|e|i|ö|ü=e}}<noinclude>{{tcat|inflsub}}</noinclude> einbwhc2v48cdl337yaqpydwig17j8n 396246 396245 2026-06-03T16:41:22Z 咽頭べさ 33 396246 wikitext text/x-wiki {{#switch:{{{1}}}|a|ı|o|u=a|ä|e|i|ö|ü=e}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude> gpq6sq1iz3ptzfd4oi6gzndxn0ur7k9 ထာမ်ပလိက်:crh-v2 10 295599 396247 2026-06-03T16:42:34Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#switch:{{{1}}}|a|ı|o|u=ı|ä|e|i|ö|ü=i}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude>" 396247 wikitext text/x-wiki {{#switch:{{{1}}}|a|ı|o|u=ı|ä|e|i|ö|ü=i}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude> e6p06edagbwsv3hh51kwgce0cfer3k2 ထာမ်ပလိက်:crh-k 10 295600 396248 2026-06-03T16:44:16Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#switch:{{{1}}}|a|ı|o|u=q|ä|e|i|ö|ü=k}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude>" 396248 wikitext text/x-wiki {{#switch:{{{1}}}|a|ı|o|u=q|ä|e|i|ö|ü=k}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude> tju7lv57bv3tdqtz7gb00f4r6nlteby ထာမ်ပလိက်:crh-g 10 295601 396249 2026-06-03T16:45:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#switch:{{{1}}}|a|ı|o|u=ğ|ä|e|i|ö|ü=g}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude>" 396249 wikitext text/x-wiki {{#switch:{{{1}}}|a|ı|o|u=ğ|ä|e|i|ö|ü=g}}<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ခရိုၚ်မာၚ်တတာဂမၠိုၚ်]]</noinclude> ly70o1238nuce07wrtx2m0vhgooobwn ထာမ်ပလိက်:da-noun-infl 10 295602 396252 2026-06-03T16:53:03Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:da-noun-infl]] ဇရေင် [[ထာမ်ပလိက်:da-decl]] 396252 wikitext text/x-wiki #REDIRECT [[ထာမ်ပလိက်:da-decl]] 7ukxykisldy13ciuhlpki53j1rc3jak ထာမ်ပလိက်:da-decl/documentation 10 295603 396253 2026-06-03T16:54:20Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{isAccelerated}} In many cases the usage is the same as {{temp|da-noun}}. The appropriate header for this template is '''Declension''', not '''Inflection'''. Adjective + noun phrases may be taken care of by {{temp|da-adj-noun-infl}}. ==Usage== ;Unnamed arguments # the suffix for the singular definite: en, n, et or t; otherwise it is taken as the complete word. If that is used the gender..." 396253 wikitext text/x-wiki {{documentation subpage}} {{isAccelerated}} In many cases the usage is the same as {{temp|da-noun}}. The appropriate header for this template is '''Declension''', not '''Inflection'''. Adjective + noun phrases may be taken care of by {{temp|da-adj-noun-infl}}. ==Usage== ;Unnamed arguments # the suffix for the singular definite: en, n, et or t; otherwise it is taken as the complete word. If that is used the gender must be given with the argument "g". # the suffix for the plural indefinite: er, r, e; if empty plural indefinite is the same as singular indefinite and the plural definite gets the ending "ene", otherwise it is taken as the complete word. # plural definite (ne in special cases with syncope, -en, -e, -ne) # genitive singular indefinite # genitive singular definite # genitive plural indefinite # genitive plural definite ; Named arguments * '''n=sg''': for nouns with no plural forms * '''g''': the gender, ''c'', ''n'' or ''b'', for [[common gender|common]], [[neuter gender|neuter]] and both genders, respectively; if the first unnamed argument is one of "en|n|et|t" it is not needed, but else it should be given * '''dc=1''': for when the ultimate consonant is doubled in declensions * '''ga=1''': for when the genitive singular indefinite is the lemma with an apostrophe appended * '''base''': is the singular indefinite; it defaults to PAGENAME, and is usually not needed * '''stem''': in cases where a suffix is dropped in declensions, such as {{m|da|museum}} (museet, museer, museerne); stem=muse, 1=et, 2=er. * '''sg-def-2''': for if there are two correct variations of the singular definite; must be the complete word * '''pl-indef-2''': for if there are two correct variations of the plural indefinite; must be the complete word * '''pl-def-2''': for if there are two correct variations of the plural definite; must be the complete word * '''gen-sg-def-2''': for if there are two correct variations of the genitive singular definite; must be the complete word * '''gen-pl-indef-2''': for if there are two correct variations of the genitive plural indefinite; must be the complete word * '''gen-pl-def-2''': for if there are two correct variations of the genitive plural definite; must be the complete word ==Examples== *'''[[blomst]]''' -en, -er :<nowiki>{{da-decl|en|er}}</nowiki> *'''[[bolle]]''' -n, -r :<nowiki>{{da-decl|n|r}}</nowiki> *'''[[hund]]''' -en, -e :<nowiki>{{da-decl|en|e}}</nowiki> *'''[[bom]]''' -men -me In this case the endings are really -en, -e, and "m" is doubled, so '''dc=1''' :<nowiki>{{da-decl|en|e|dc=1}}</nowiki> *'''[[hun]]''' -nen, -ner :<nowiki>{{da-decl|en|er|dc=1}}</nowiki> *'''[[ord]]''' -et, ord -ene Plural indefinite is the same as singular indefinite :<nowiki>{{da-decl|et}}</nowiki> *'''[[springer]]''' -en, -e, springerne There is a syncope of the plural e. :<nowiki>{{da-decl|en|e|ne}}</nowiki> *'''[[mus]]''' -en, mus, -ene Words ending in s, z or x have an apostrophe in genitive form, so here the full word has to be supplied for arguments 4 and 6 :<nowiki>{{da-decl|en|||mus'||mus'}}</nowiki> *'''[[mand]]''' -en, mænd, mændene The vowel is changed in plural forms, so here the full word has to be supplied for arguments 2 and 3 :<nowiki>{{da-decl|en|mænd|mændene}}</nowiki> *'''[[offer]]''' of(fe)ret, ofre Two alternatives for the singular definite, and irregular spelling #<nowiki>{{da-decl|stem=ofr|et|e|sg-def-2=offeret}}</nowiki>, or #<nowiki>{{da-decl|et|ofre|ofrene|sg-def-2=ofret}}</nowiki> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဒိန်နေတ်ဂမၠိုၚ်| ]] </includeonly> boz0ce2sd0qr6ogjklbvwc41fxmhblj ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဒိန်နေတ်ဂမၠိုၚ် 14 295604 396254 2026-06-03T16:55:58Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဒိန်နေတ်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဒ]]" 396254 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဒိန်နေတ်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဒ]] mgcraaa05s3gmrs4lkvw2f7ra822s69 ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဒိန်နေတ်ဂမၠိုၚ် 14 295605 396255 2026-06-03T16:57:22Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ဒိန်နေတ်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဒ]]" 396255 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်ဒိန်နေတ်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဒ]] nfyu7qai42dcvm38fjqkv30zvz26c3b ထာမ်ပလိက်:da-noun-infl-base 10 295606 396256 2026-06-03T17:01:45Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|error}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|da||{{{sg-indef}}}}}|palette=brown|tall=yes}} ! rowspan="2" | {{#switch:{{{g}}}|c=common|n=neuter|b=either|}}<br/>gender ! colspan="2" | ကိုန်ဨကဝုစ် ! colspan="2" | ကိုန်ဗဟုဝစ် |- ! class="secondary" | ဟွံချ..." 396256 wikitext text/x-wiki {{#invoke:checkparams|error}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|da||{{{sg-indef}}}}}|palette=brown|tall=yes}} ! rowspan="2" | {{#switch:{{{g}}}|c=common|n=neuter|b=either|}}<br/>gender ! colspan="2" | ကိုန်ဨကဝုစ် ! colspan="2" | ကိုန်ဗဟုဝစ် |- ! class="secondary" | ဟွံချိုတ်ပၠိုတ် ! class="secondary" | မချိုတ်ပၠိုတ် ! class="secondary" | ဟွံချိုတ်ပၠိုတ် ! class="secondary" | မချိုတ်ပၠိုတ် |- ! [[nominative case|မဒုၚ်ယၟု]] | <!-- -->{{l-self|da|{{{sg-indef}}}}} | <!-- -->{{l-self|da|accel-form=def{{!}}s|{{{sg-def}}}}}<!-- -->{{#if:{{{sg-def-2|}}}|<br/>{{l-self|da|accel-form=def{{!}}s|{{{sg-def-2|}}}}}}} | <!-- -->{{l-self|da|accel-form=indef{{!}}p|{{{pl-indef}}}}}<!-- -->{{#if:{{{pl-indef-2|}}}|<br/>{{l-self|da|accel-form=indef{{!}}p|{{{pl-indef-2|}}}}}}}<!-- -->{{#if:{{{pl-indef-3|}}}|<br/>{{l-self|da|accel-form=indef{{!}}p|{{{pl-indef-3|}}}}}}} | <!-- -->{{l-self|da|accel-form=def{{!}}p|{{{pl-def}}}}}<!-- -->{{#if:{{{pl-def-2|}}}|<br/>{{l-self|da|accel-form=def{{!}}p|{{{pl-def-2|}}}}}}}<!-- -->{{#if:{{{pl-def-3|}}}|<br/>{{l-self|da|accel-form=def{{!}}p|{{{pl-def-3|}}}}}}} |- ! [[genitive case|ဗဳဇဂကူ]] | <!-- -->{{l-self|da|accel-form=indef{{!}}gen{{!}}s|{{{gen-sg-indef}}}}}<!-- -->{{#if:{{{gen-sg-indef-2|}}}|<br/>{{l-self|da|accel-form=indef{{!}}gen{{!}}s|{{{gen-sg-indef-2}}}}}}}<!-- -->{{#if:{{{gen-sg-indef-3|}}}|<br/>{{l-self|da|accel-form=indef{{!}}gen{{!}}s|{{{gen-sg-indef-3}}}}}}} | <!-- -->{{l-self|da|accel-form=def{{!}}gen{{!}}s|{{{gen-sg-def}}}}}<!-- -->{{#if:{{{gen-sg-def-2|}}}|<br/>{{l-self|da|accel-form=def{{!}}gen{{!}}s|{{{gen-sg-def-2|}}}}}}} | <!-- -->{{l-self|da|accel-form=indef{{!}}gen{{!}}p|{{{gen-pl-indef}}}}}<!-- -->{{#if:{{{gen-pl-indef-2|}}}|<br/>{{l-self|da|accel-form=indef{{!}}gen{{!}}p|{{{gen-pl-indef-2|}}}}}}} | <!-- -->{{l-self|da|accel-form=def{{!}}gen{{!}}p|{{{gen-pl-def}}}}}<!-- -->{{#if:{{{gen-pl-def-2|}}}|<br/>{{l-self|da|accel-form=def{{!}}gen{{!}}p|{{{gen-pl-def-2|}}}}}}}<!-- -->{{#if:{{{gen-pl-def-3|}}}|<br/>{{l-self|da|accel-form=def{{!}}gen{{!}}p|{{{gen-pl-def-3|}}}}}}} {{inflection-table-bottom|notes={{{notes|}}}}}<!-- --><noinclude>{{documentation}}</noinclude> jrox7a7sk0n5i05tfztchg8483s7khf ထာမ်ပလိက်:da-noun-infl-base/documentation 10 295607 396257 2026-06-03T17:02:58Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{isAccelerated}} ;Basic use: <pre>{{da-noun-infl-base | sg-indef = | sg-def = | pl-indef = | pl-def = | gen-sg-indef = | gen-sg-def = | gen-pl-indef = | gen-pl-def = | g = }}</pre> ;Full use: <pre>{{da-noun-infl-base | sg-indef = | sg-def = | sg-def-2 = | pl-indef = | pl-indef-2 = | pl-def = | pl-def-2 = | gen-s..." 396257 wikitext text/x-wiki {{documentation subpage}} {{isAccelerated}} ;Basic use: <pre>{{da-noun-infl-base | sg-indef = | sg-def = | pl-indef = | pl-def = | gen-sg-indef = | gen-sg-def = | gen-pl-indef = | gen-pl-def = | g = }}</pre> ;Full use: <pre>{{da-noun-infl-base | sg-indef = | sg-def = | sg-def-2 = | pl-indef = | pl-indef-2 = | pl-def = | pl-def-2 = | gen-sg-indef = | gen-sg-def = | gen-sg-def-2 = | gen-pl-indef = | gen-pl-indef-2 = | gen-pl-def = | gen-pl-def-2 = | g = }}</pre> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဒိန်နေတ်ဂမၠိုၚ်|infl-base]] </includeonly> hlvuur8p57gszt6uwggufs7i13xssjg ထာမ်ပလိက်:da-noun-infl-unc-base 10 295608 396258 2026-06-03T17:06:44Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|error|gen-sg-indef-3,pl-indef-2,pl-def-3,pl-indef,gen-pl-indef-2,gen-pl-def,gen-pl-def-2,gen-pl-def-3,pl-indef-3,gen-pl-indef,pl-def-2,pl-def}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|da||{{{sg-indef}}}}}|palette=brown|tall=yes}} ! rowspan="2" | {{#switch:{{{g}}}|c=common|n=neuter|b=either }}<br/>gender ! co..." 396258 wikitext text/x-wiki {{#invoke:checkparams|error|gen-sg-indef-3,pl-indef-2,pl-def-3,pl-indef,gen-pl-indef-2,gen-pl-def,gen-pl-def-2,gen-pl-def-3,pl-indef-3,gen-pl-indef,pl-def-2,pl-def}}<!-- Validate template parameters -->{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|da||{{{sg-indef}}}}}|palette=brown|tall=yes}} ! rowspan="2" | {{#switch:{{{g}}}|c=common|n=neuter|b=either }}<br/>gender ! colspan="2" | ကိုန်ဨကဝုစ် |- ! class="secondary" | ဟွံချိုတ်ပၠိုတ် ! class="secondary" | မချိုတ်ပၠိုတ် |- ! [[nominative case|မဒုၚ်ယၟု]] | <!-- -->{{l-self|da|{{{sg-indef}}}}} | <!-- -->{{l-self|da|{{{sg-def}}}|accel-form=def{{!}}s}}<!-- -->{{#if:{{{sg-def-2|}}}|<br/>{{l-self|da|{{{sg-def-2|}}}|accel-form=def{{!}}s}}}} |- ! [[genitive case|ဗဳဇဂကူ]] | <!-- -->{{l-self|da|{{{gen-sg-indef}}}|accel-form=indef{{!}}gen{{!}}s}}<!-- -->{{#if:{{{gen-sg-indef-2|}}}|<br/>{{l-self|da|{{{gen-sg-indef-2}}}|indef{{!}}gen{{!}}s}}}} | <!-- -->{{l-self|da|{{{gen-sg-def}}}|accel-form=def{{!}}gen{{!}}s}}<!-- -->{{#if:{{{gen-sg-def-2|}}}|<br/>{{l-self|da|{{{gen-sg-def-2|}}}|accel-form=def{{!}}gen{{!}}s}}}} {{inflection-table-bottom|notes={{{notes|}}}}}<!-- --><noinclude>{{documentation}}</noinclude> to3kr25krm1v4gds3rc86dx2zqk3dh0 ထာမ်ပလိက်:da-noun-infl-unc-base/documentation 10 295609 396259 2026-06-03T17:07:40Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} This template is used by {{temp|da-noun-infl}} instead of {{temp|da-noun-infl-base}} if '''n''' is set to ''sg''. <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဒိန်နေတ်ဂမၠိုၚ်|infl-unc-base]] </includeonly>" 396259 wikitext text/x-wiki {{documentation subpage}} This template is used by {{temp|da-noun-infl}} instead of {{temp|da-noun-infl-base}} if '''n''' is set to ''sg''. <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဒိန်နေတ်ဂမၠိုၚ်|infl-unc-base]] </includeonly> 4spmeroo20roiiajl6bdkvjt0ej7e7n မဝ်ဂျူ:sk-pron 828 295610 396261 2026-06-03T17:10:51Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local export = {} -- ============================================================================= -- [[ DATA TABLES ]] -- ============================================================================= -- [[ 1. Phonological Sets ]] -- local diphthongs_set = { ["ia"]=true, ["ie"]=true, ["iu"]=true, ["ô"]=true } local bigraphs_set = { ["ch"]=true, ["dz"]=true, ["dž"]=true } -- Combined Vowels (Short & Long + Foreig..." 396261 Scribunto text/plain local export = {} -- ============================================================================= -- [[ DATA TABLES ]] -- ============================================================================= -- [[ 1. Phonological Sets ]] -- local diphthongs_set = { ["ia"]=true, ["ie"]=true, ["iu"]=true, ["ô"]=true } local bigraphs_set = { ["ch"]=true, ["dz"]=true, ["dž"]=true } -- Combined Vowels (Short & Long + Foreign) local vowels_set = { ["a"]=true, ["e"]=true, ["i"]=true, ["o"]=true, ["u"]=true, ["y"]=true, ["ä"]=true, ["ö"]=true, ["ü"]=true, ["á"]=true, ["é"]=true, ["í"]=true, ["ó"]=true, ["ú"]=true, ["ý"]=true, ["ő"]=true, ["ű"]=true } -- Voicing & Sonorants local sonorants = { ['m']=true, ['n']=true, ['ň']=true, ['l']=true, ['ľ']=true, ['ĺ']=true, ['r']=true, ['ŕ']=true, ['j']=true, ['v']=true } local voiced_paired = { ['b']=true, ['d']=true, ['ď']=true, ['g']=true, ['dz']=true, ['dž']=true, ['h']=true, ['z']=true, ['ž']=true, ['w']=true } local voiceless_paired = { ['p']=true, ['t']=true, ['ť']=true, ['k']=true, ['c']=true, ['č']=true, ['ch']=true, ['s']=true, ['š']=true, ['f']=true } local voicing_map = { -- Voiced to Voiceless ['b']='p', ['d']='t', ['ď']='ť', ['g']='k', ['dz']='c', ['dž']='č', ['h']='ch', ['w']='f', ['z']='s', ['ž']='š', -- Voiceless to Voiced ['p']='b', ['t']='d', ['ť']='ď', ['k']='g', ['c']='dz', ['č']='dž', ['ch']='h', ['f']='w', ['s']='z', ['š']='ž' } -- [[ 2. Assimilation & Encoding ]] -- local dental_mergers = { ['z']='dzdz', ['dz']='dzdz', ['s']='cc', ['c']='cc', ['ž']='dždž', ['dž']='dždž', ['š']='čč', ['č']='čč' } -- Mergers: Encodes t.s -> 15, d.z -> 26, etc. local c1_enc = {['t']=1, ['d']=2, ['ť']=3, ['ď']=4} local c2_enc = { ['c']=1, ['dz']=2, ['č']=3, ['dž']=4, ['s']=5, ['z']=6, ['š']=7, ['ž']=8 } -- Decoding: Used by IPA renderer to convert "15" -> t.ts local c1_dec = { 't', 'd', 'c', 'ɟ' } local c2_dec = { 't͡s', 'd͡z', 't͡ʃ', 'd͡ʒ', 's', 'z', 'ʃ', 'ʒ' } -- [[ 3. Morphological & Lexical Exceptions ]] -- local prefixes = { ['pod']=true, ['ob']=true, ['od']=true, ['ráz']=true, ['roz']=true, ['bez']=true, ['ab']=true, ['vz']=true, ['pred']=true, ['nad']=true } local prepositions_set = { ["bez"]=true, ["cez"]=true, ["do"]=true, ["k"]=true, ["ku"]=true, ["na"]=true, ["nad"]=true, ["o"]=true, ["od"]=true, ["po"]=true, ["pod"]=true, ["pre"]=true, ["pred"]=true, ["pri"]=true, ["s"]=true, ["so"]=true, ["u"]=true, ["v"]=true, ["vo"]=true, ["z"]=true, ["za"]=true, ["zo"]=true } local clitics = { ["byť"]=true, ["som"]=true, ["si"]=true, ["je"]=true, ["sme"]=true, ["ste"]=true, ["sú"]=true, ["bol"]=true, ["mi"]=true, ["ti"]=true, ["mu"]=true, ["jej"]=true, ["ma"]=true, ["ťa"]=true, ["sa"]=true, ["ho"]=true, ["ju"]=true, ["nám"]=true, ["vám"]=true, ["im"]=true, ["nás"]=true, ["vás"]=true, ["ich"]=true, ["ten"]=true, ["tá"]=true, ["to"]=true, ["on"]=true, ["a"]=true, ["i"]=true, ["aj"]=true, ["že"]=true, ["keď"]=true, ["až"]=true, ["len"]=true, ["či"]=true, ["kde"]=true, ["ba"]=true, ["ak"]=true, ["už"]=true, ["by"]=true } local preposition_blockers = { ['mnou']=true, ['mne']=true, ['tebou']=true, ['ňou']=true, ['ním']=true, ['nami']=true, ['vami']=true, ['nimi']=true, ['tebe']=true, ['nemu']=true, ['nej']=true, ['nám']=true, ['vám']=true, ['nim']=true } -- [[ 4. IPA Output Maps ]] -- local ipa_map = { -- Vowels ['a']='a', ['á']='aː', ['ä']='æ', ['e']='e', ['é']='eː', ['i']='i', ['í']='iː', ['o']='ɔ', ['ó']='ɔː', ['ô']='u̯ɔ', ['u']='u', ['ú']='uː', ['y']='i', ['ý']='iː', ['ö']='ø', ['ő']='øː', ['ü']='y', ['ű']='yː', -- Consonants ['b']='b', ['c']='t͡s', ['č']='t͡ʃ', ['d']='d', ['ď']='ɟ', ['g']='ɡ', ['h']='ɦ', ['j']='j', ['k']='k', ['l']='l', ['ľ']='ʎ', ['m']='m', ['n']='n', ['ň']='ɲ', ['p']='p', ['r']='r', ['ř']='r̝', ['ŕ']='r̩ː', ['ĺ']='l̩ː', ['s']='s', ['š']='ʃ', ['t']='t', ['ť']='c', ['z']='z', ['ž']='ʒ', ['x']='x', -- Special ['v']='v', ['w']='w', ['F']='F', ['f']='f', ['ů']='ů', ["'"]='ˈ', -- Digraphs/Multigraphs ['dz']='d͡z', ['dž']='d͡ʒ', ['ch']='x', ['dzdz']='d͡zː', ['dždž']='d͡ʒː', ['ia']='ɪ̯a', ['ie']='ɪ̯e', ['iu']='ɪ̯u' } local variant_map = { ["H"]={"ɣ","ɦ"}, ["W"]={"ʋ","v"}, ["U"]={"u̯","ʋ"}, ["J"]={"ɪ̯","j"}, ["N"]={"n","n̠"} } -- Module-level state variables local IS_MO_VARIANT = false local NAMESPACE = "" local PAGENAME = "" local LOAN = 0 local HARD_SUFFIX = 0 local AS_IMP = 0 -- ============================================================================= -- [[ HELPER FUNCTIONS ]] -- ============================================================================= function get_voiced_counterpart(char) return voicing_map[char] end -- Tokenizer (Preserves digraphs) function get_graphemes(word) local units = {} local len = mw.ustring.len(word) local i = 1 local is_loan = (LOAN == 1) while i <= len do local two_char = mw.ustring.sub(word, i, i + 1) if bigraphs_set[two_char] or (diphthongs_set[two_char] and not is_loan) then table.insert(units, two_char) i = i + 2 else table.insert(units, mw.ustring.sub(word, i, i)) i = i + 1 end end return units end -- Resolve Cluster (Contact Assimilation Logic) function resolve_cluster(c1, c2, is_boundary) -- GUARD: v/f complex logic if c1 == 'v' or c1 == 'f' then return nil end -- 1. SPECIAL: <h> or <ch> logic if c1 == 'ch' or c1 == 'h' then if (voiced_paired[c2] or sonorants[c2]) and is_boundary then return 'H' .. c2 end end -- 2. Standard Assimilation local c1_new = c1 if (voiceless_paired[c1] and (voiced_paired[c2] or (is_boundary and (sonorants[c2] or vowels_set[c2])))) or (voiced_paired[c1] and voiceless_paired[c2]) then c1_new = voicing_map[c1] or c1 end -- 3. Mergers & Gemination if c1_enc[c1_new] and dental_mergers[c2] then if is_boundary then local d1, d2 = c1_enc[c1_new], c2_enc[c2] if d1 and d2 then return d1 .. d2 end end return dental_mergers[c2] end if c1_new ~= c1 then return c1_new .. c2 end return nil end function apply_assimilation(tokens, i, j, is_boundary) if IS_MO_VARIANT and i == #tokens - 3 then return end local res = resolve_cluster(tokens[i], tokens[j], is_boundary) if res then local res_tokens = get_graphemes(res) if #res_tokens == 2 then tokens[i] = res_tokens[1]; tokens[j] = res_tokens[2] elseif #res_tokens == 1 then tokens[i] = res_tokens[1]; tokens[j] = "" end end end -- Syllable Splitter function split_into_syllables(word) local units = get_graphemes(word) local nuc, syl, len = {}, {}, #units -- Helper: Check if index k is a Nucleus local function is_nuc(k) local u = units[k]; if not u then return false end if diphthongs_set[u] or vowels_set[u] then return true end if not (u=='r' or u=='l' or u=='ŕ' or u=='ĺ') then return false end -- Check neighbors (skipping non-phonemic chars) local function v(i, d) while i>0 and i<=len do local t=units[i] if vowels_set[t] or diphthongs_set[t] then return true end if t~="'" and t~="-" and t~=" " and t~="_" then return false end i=i+d end end return not (v(k-1, -1) or v(k+1, 1)) end for i=1,len do if is_nuc(i) then table.insert(nuc, i) end end if #nuc==0 then return {table.concat(units)} end local start = 1 for k = 1, #nuc - 1 do local curr, next_n = nuc[k], nuc[k+1] local split = curr -- Default: Split after vowel (V-CV) local c_cnt, first_c = 0, nil for j = curr + 1, next_n - 1 do local c = units[j] if c=="-" or c==" " then split=j; c_cnt=-1; break -- 1. Hard Boundary elseif c=="'" then split=j-1; c_cnt=-1; break -- 2. Stress Boundary elseif c~="." then c_cnt=c_cnt+1; first_c = first_c or j end end if c_cnt >= 2 then split = first_c end -- 3. Cluster Rule (VC-CV) table.insert(syl, table.concat(units, "", start, split)) start = split + 1 end table.insert(syl, table.concat(units, "", start)) return syl end -- [[ Core IPA Transformation Logic ]] -- local function ipa_transform_worker(word) -- 1. Preprocess: Strip punctuation but map boundaries local bound, idx = {}, 0 word = mw.ustring.gsub(word, ".", function(c) if c == "-" or c == "." then bound[idx] = true; return "" end idx = idx + 1 end) -- Returns cleaned word, populates 'bound' local sub = mw.ustring.sub local w_len, res, i = idx, {}, 1 local function is_C(c) return not c or c == "" or (not vowels_set[c] and not diphthongs_set[c]) end while i <= w_len do local c1 = sub(word, i, i) if c1 == "+" then i = i + 1 else local nxt = sub(word, i+1, i+1) local c2_raw = (nxt == "+") and sub(word, i+2, i+2) or nxt local c2, c4 = c1 .. c2_raw, sub(word, i, i+3) local jump = (nxt == "+") and 1 or 0 local sym, step, raw = nil, 1, c1 if c4 == "dzdz" or c4 == "dždž" then sym, step, raw = ipa_map[c4], 4, c4 elseif (c1 == c2_raw or c2 == "čš") and ipa_map[c1] and not vowels_set[c1] then sym, step, raw = ipa_map[c1] .. "ː", 2 + jump, c1 elseif (ipa_map[c2] and not diphthongs_set[c2]) or (diphthongs_set[c2] and (LOAN~=1 or jump>0) and not bound[i]) then sym, step, raw = ipa_map[c2], 2 + jump, c2 -- treat as diphthong only if native or explicitly marked with + else sym = ipa_map[c1] or c1 end if sym then if (raw=='r' or raw=='l') and is_C(i>1 and sub(word,i-1,i-1)) and is_C(sub(word,i+step,i+step)) then sym = sym .. '̩' -- mark liquid as syllabic if sandwiched between non-vowels end table.insert(res, sym) end i = i + step end end local out = table.concat(res) -- Post-processing for loanword endings (-ovan-) if LOAN == 1 then local sfx = mw.ustring.match(word, ".*ovan(.+)$") if sfx then local m = ipa_map local fix = { ["ie"]=m["ie"], ["ia"]=m["ia"], ["iu"]=m["iu"], ["í"]=m["í"], ["ím"]=m["í"]..(m["m"] or 'm'), ["iam"]=m["ia"]..(m["m"] or 'm'), ["iach"]=m["ia"]..(m["x"] or 'x'), ["iami"]=m["ia"]..(m["m"] or 'm')..(m["i"] or 'i') } if fix[sfx] then local bad = (m["n"] or 'n') .. sfx:gsub(".", function(c) return m[c] or c end) out = mw.ustring.gsub(out, bad:gsub("[%p]", "%%%0") .. "$", (m['ň'] or 'ɲ') .. fix[sfx]) -- correct [n] to [ň] before soft vowels in loan suffixes end end end return out end -- [[ 2. STAGE 2: PHONETIC RESOLVER ]] -- function resolve_phonetic_base(base_text) local res = {} local len = mw.ustring.len(base_text) local i = 1 -- Map for standard phonetic realization local map = { ['v']='ʋ', ['w']='v', ['F']='v', ['f']='f', ['ů']='u̯', ['I']='ɪ̯' } local sub = mw.ustring.sub -- Local ref while i <= len do local c = sub(base_text, i, i) local symbol = map[c] or c local next_c = (i < len) and sub(base_text, i+1, i+1) or "" local next_resolved = map[next_c] or next_c -- Apply FULL Nasal Assimilation if c == 'm' then if next_resolved == 'f' or next_resolved == 'v' or next_resolved == 'ʋ' then symbol = 'ɱ' end elseif c == 'n' then if next_resolved == 'k' or next_resolved == 'ɡ' then symbol = 'ŋ' elseif next_resolved == 's' or next_resolved == 'z' or next_resolved == 'ʃ' or next_resolved == 'ʒ' then symbol = 'N' elseif next_resolved == 'x' then symbol = 'ɰ̃' elseif next_resolved == 'p' or next_resolved == 'b' then symbol = 'm' end end table.insert(res, symbol) i = i + 1 end return table.concat(res) end -- [[ 3. FINAL GENERATION ]] -- local function expand_variants(txt) local find, sub, gsub = mw.ustring.find, mw.ustring.sub, mw.ustring.gsub -- 1. Digits: Binary Branch (All-Split vs All-Merged) if find(txt, "%d[ˈ%s_]*%d") then local res = {} for m = 1, 2 do local s = gsub(txt, "(%d)([ˈ%s_]*)(%d)", function(d1, sep, d2) d1, d2 = tonumber(d1), tonumber(d2) if m == 1 then -- Split (Unassimilated) local f = ((d1+d2)%2==1) and (d1 + (d2%2==0 and 1 or -1)) or d1 return (c1_dec[f] or "") .. sep .. (c2_dec[d2] or "") else -- Merged (Assimilated) local c = c2_dec[d2>4 and d2-4 or d2] or "" -- If stressed: Unreleased + Short (t̚ ˈt͡s). If not: Long (t͡sː) return find(sep, "ˈ") and (sub(c,1,1).."̚ ˈ"..c) or (c.."ː") end end) for _, v in ipairs(expand_variants(s)) do table.insert(res, v) end end return res end -- 2. Letters: Recursive Expansion (HWUJN) local s, e, k = find(txt, "([HWUJN])") if not s then return {txt} end -- Base case local res, h, t = {}, sub(txt, 1, s-1), sub(txt, e+1) for _, r in ipairs(variant_map[k]) do for _, sub in ipairs(expand_variants(h..r..t)) do table.insert(res, sub) end end return res end local function format_ipa_output(res, frame) local distinct = table.concat(res.high) ~= table.concat(res.low) local args = { "sk", "/" .. res.phonemic .. "/" } local function add(list, tag) for i, ipa in ipairs(list) do local qs = {} if distinct and tag and i == 1 then table.insert(qs, tag) end if mw.ustring.find(ipa, "ɦ ?ˈ?ɦ") then table.insert(qs, "rare") end local q = #qs > 0 and "<q:" .. table.concat(qs, ", ") .. ">" or "" table.insert(args, "[" .. ipa .. "]" .. q) end end add(res.high, "high register") if distinct then add(res.low, "common") end return frame:expandTemplate{ title = "IPA", args = args } end local function get_ipa_nuclei(ipa) local s = mw.ustring.gsub(ipa, "[/ %[%]ˈ%.]", "") local nuclei, skip, sub = {}, 0, mw.ustring.sub mw.ustring.gsub(s, "()([rluɪaæeiɔuøy])", function(p, c) if p < skip then return end local nuc, len = nil, 1 local nxt = sub(s, p+1, p+1) if (c=="r" or c=="l") and nxt=="̩" then len = (sub(s, p+2, p+2)=="ː") and 3 or 2 nuc = sub(s, p, p+len-1) elseif (c=="u" or c=="ɪ") and nxt=="̯" then len = 3; nuc = sub(s, p, p+2) elseif mw.ustring.find(c, "[aæeiɔuøy]") then if sub(s, p+1, p+2) == "u̯" then len = 3; nuc = sub(s, p, p+2) else len = (nxt=="ː") and 2 or 1; nuc = sub(s, p, p+len-1) end end if nuc then table.insert(nuclei, {ipa=nuc, s=p, e=p+len-1}); skip = p+len end end) return nuclei, s end local function format_rhymes(frame, nuclei, s) local c = #nuclei if c == 0 then return "" end local rhyme = mw.ustring.sub(s, (c > 1 and nuclei[c-1] or nuclei[1]).s) return "\n*" .. frame:expandTemplate{title="rhymes", args={"sk", rhyme, s=c}} end local function format_hyphenation(word, ipa, frame, respelling, nuclei) if #nuclei <= 1 then return "" end local sub, find, lower, len = mw.ustring.sub, mw.ustring.find, mw.ustring.lower, mw.ustring.len local w_lower = lower(word) -- 1. Parse Respelling (Boundaries & Forbidden Nuclei) local forced, forbidden, idx, last = {}, {}, 0, "" if respelling then local clean_check = mw.ustring.gsub(lower(respelling), "[%.%-%+]", "") if clean_check == w_lower then for i = 1, len(respelling) do local c = sub(respelling, i, i) if c == "+" then if last ~= "i" and last ~= "í" then forbidden[idx + 1] = true end elseif c:match("[%.%-]") then if idx > 0 then forced[idx] = true end else idx = idx + 1; last = lower(c) end end end end local map = { ['a']='a', ['aː']='á', ['æ']='ä', ['e']='e', ['eː']='é', ['i']='[iy]', ['iː']='[íý]', ['o']='o', ['oː']='ó', ['ɔ']='o', ['ɔː']='ó', ['u']='u', ['uː']='ú', ['u̯ɔ']='ô', ['ɔu̯']='ou', ['ø']='ö', ['øː']='ő', ['y']='ü', ['yː']='ű', ['ɪ̯a']='ia', ['ɪ̯e']='ie', ['ɪ̯u']='iu', ['r̩']='r', ['r̩ː']='ŕ', ['l̩']='l', ['l̩ː']='ĺ' } -- Helper: Find next valid nucleus (skips forbidden off-glides) local function get_nuc(pat, start) while true do local s, e = find(w_lower, pat, start) if not s or not forbidden[s] then return s, e end start = s + 1 end end local args, pos = {"sk"}, 1 local seg_start = 1 for i = 1, #nuclei do local s, e = get_nuc(map[nuclei[i].ipa] or ".", pos) if not s then return "" end if i < #nuclei then local s2, _ = get_nuc(map[nuclei[i+1].ipa] or ".", e + 1) if not s2 then return "" end -- Default: Split before last consonant (V-CV) or between consonants (VC-CV) local clust = sub(w_lower, e+1, s2-1) -- If cluster has space, DO NOT split. if find(clust, " ") then pos = e + 1 else local c_len = len(clust) local off = 0 if c_len >= 2 then local dig = sub(clust, 1, 2) off = (dig == "ch" or dig == "dz" or dig == "dž") and (c_len > 2 and 2 or 0) or 1 end for k = e, s2 - 1 do if forced[k] then off = k - e; break end end table.insert(args, sub(word, seg_start, e + off)) seg_start = e + off + 1 pos = e + off + 1 end else table.insert(args, sub(word, seg_start)) end end return "\n*" .. frame:expandTemplate{title="hyph", args=args} end -- ============================================================================= -- [[ PROCESSING STEPS ]] -- ============================================================================= function step_foreign_graphemes(word) word = mw.ustring.lower(word) word = mw.ustring.gsub(word, "ů", "ú") word = mw.ustring.gsub(word, "x", "ks") word = mw.ustring.gsub(word, "w", "v") word = mw.ustring.gsub(word, "qu", "kv") word = mw.ustring.gsub(word, "[,']", "") return word end function step_softening(w) if LOAN == 1 then return w end local soft = {['d']='ď',['t']='ť',['n']='ň',['l']='ľ'} local sub = mw.ustring.sub local res = {} for i = 1, mw.ustring.len(w) do local c = sub(w, i, i) local s = false if soft[c] then local n1 = sub(w, i+1, i+1) local n2 = sub(w, i+1, i+2) if n2=="ia" or n2=="ie" or n2=="iu" then s = true elseif n1=="i" or n1=="í" or n1=="e" then s = true if HARD_SUFFIX == 1 then local function E(k) local x = sub(w,k,k); return x=="" or x==" " end local n3 = sub(w, i+1, i+3) if (n1=="i" or n1=="í" or n1=="e") and E(i+2) then s = false elseif n2=="ej" and E(i+3) then s = false elseif (n3=="eho" or n3=="emu") and E(i+4) then s = false end end end end table.insert(res, s and soft[c] or c) end return table.concat(res) end function step_prosody(word) -- 1. Merge Prepositions word = mw.ustring.gsub(word, "%f[%a](%a+) +", function(w) return prepositions_set[mw.ustring.lower(w)] and (w .. "_") or nil end) -- 2. Add Stress return mw.ustring.gsub(word, "%S+", function(w) local raw = mw.ustring.lower(mw.ustring.gsub(w, "_", "")) -- Exclusions: Clitics OR Starts with hyphen OR Single letter OR No syllabic nucleus if clitics[raw] or mw.ustring.sub(w, 1, 1) == "-" or mw.ustring.sub(w, -1) == "-" or mw.ustring.len(w) == 1 or not mw.ustring.find(raw, "[aáäeéiíoóuúyýöőüűôrŕlĺ]") then return w end return "'" .. w end) end function step_simplification(word) local patterns = { "s[tť]s[tk]", "[pd][tz]sk", "[tďdz]st", "[ztd]šť", "[zdt]sk", "ptč" } local function resolve(w) local c1 = mw.ustring.sub(w, 1, 1) if c1 == "s" then return c1 .. mw.ustring.sub(w, 4) elseif c1 == "p" then return c1 .. mw.ustring.sub(w, 3) else w = mw.ustring.gsub(w, "z", "") if mw.ustring.len(w) <= 2 then return w end local c2 = mw.ustring.sub(w, 2, 2) local head = (c2 == "s") and "c" or "č" return head .. mw.ustring.sub(w, 3) end end for _, pat in ipairs(patterns) do word = mw.ustring.gsub(word, pat, resolve) end return word end function step_assimilation(word) -- [[ 1. Pre-processing & Morphological Exceptions ]] -- word = mw.ustring.gsub(word, "('[nv]ášmu)(%f[%A])", function(match) return mw.ustring.gsub(match, "š", "ž") end) -- 2. sme -> zme (Only if surrounded by boundaries) if mw.ustring.find(word, "sme") then word = mw.ustring.gsub(mw.ustring.gsub(word, "^sme$", "zme"), "^sme(%s)", "zme%1") word = mw.ustring.gsub(mw.ustring.gsub(word, "(%s)sme$", "%1zme"), "(%s)sme(%s)", "%1zme%2") end -- A. Prefix "eks-" (eks- + vowel/voiced -> egz-) local v_set = "[aeiouyáéíóúýäôglmnňrjvzhdbžg]" word = mw.ustring.gsub(word, "^('?)eks("..v_set..")", "%1egz%2") word = mw.ustring.gsub(word, "([%s_])('?)eks("..v_set..")", "%1%2egz%3") word = mw.ustring.gsub(word, "^('?)dis("..v_set..")", "%1diz%2") word = mw.ustring.gsub(word, "([%s_])('?)dis("..v_set..")", "%1%diz%3") -- B. Preposition Vocalization (so/ku -> zo/gu) word = mw.ustring.gsub(word, "([%s'])([sk][ou])(_)([^%s%._]+)", function(before, prep, sep, next_w) if not preposition_blockers[next_w] then local voiced = (prep == "so") and "zo" or "gu" return before .. voiced .. sep .. next_w end end) -- C. Imperative Suffix "-me" (Voice preceding consonant) if AS_IMP == 1 then word = mw.ustring.gsub(word, "([ptsťkfcčš])me", function(c) return (voicing_map[c] or c) .. "me" end) end -- [[ 2. Main Assimilation Logic ]] -- local tokens = get_graphemes(word) local len = #tokens local str = table.concat(tokens) -- Check for "-mo" variant trigger if mw.ustring.find(word, "[ptsčškcfx]%.mo%f[%A]") or mw.ustring.find(word, "ch%.mo%f[%A]") then IS_MO_VARIANT = true end -- Helpers local function prev_C(k) while k >= 1 do local t=tokens[k]; if t~="'" and t~="_" and t~=" " and t~="-" and t~="." then return k end k=k-1 end end local function is_bound(k) return k<1 or k>len or tokens[k]==" " or tokens[k]=="_" or tokens[k]=="-" end local function prev_bound(k) local l, k = 0, k-1 -- Start checking before current index while k-l >= 1 do local t = tokens[k-l] if t=="'" or t=="_" or t==" " or t=="-" then break end l = l + 1 end return l end -- Init State local simple = not mw.ustring.find(str, "[ %-_]") local w_offset = (simple and tokens[1] == "'") and 1 or 0 -- p_len = Exact count of characters before 'i' local p_len = simple and (len - w_offset - 1) or prev_bound(len) -- Reverse Loop (Regressive Assimilation) for i = len, 2, -1 do -- Reset state if we crossed a word boundary if not simple and is_bound(i+1) then p_len = prev_bound(i) end local is_prefix = false -- A. Prefix Check if p_len >= 2 and p_len <= 4 then local sub = table.concat(tokens, "", i - p_len, i - 1) if prefixes[sub] then apply_assimilation(tokens, i - 1, i, true) is_prefix = true end end -- B. General Assimilation (If not prefix) if not is_prefix then local tgt = prev_C(i-1) if tgt then local is_opt = false for k = tgt + 1, i - 1 do if tokens[k]==" " or tokens[k]=="-" or tokens[k]=="_" then is_opt = true; break end end -- Handles both Devoicing (standard) and Voicing (at boundaries) apply_assimilation(tokens, tgt, i, is_opt) end end p_len = p_len - 1 end return table.concat(tokens) end function step_v_f_j_realization(word) word = mw.ustring.gsub(mw.ustring.gsub(word, "anje[lľ]", "aňɪ̯el"), "_", "") word = mw.ustring.gsub(mw.ustring.gsub(word, "%+u", "ů"), "%+i", "I") local syllables = split_into_syllables(word) local res_syls = {} local function is_nuc(c) return vowels_set[c] or diphthongs_set[c] or c=='r' or c=='l' or c=='ŕ' or c=='ĺ' end for s_i, syl in ipairs(syllables) do local s_len, res = mw.ustring.len(syl), {} local nuc_i = nil for k = 1, s_len do if is_nuc(mw.ustring.sub(syl, k, k)) then nuc_i = k; break end end for c_i = 1, s_len do local c = mw.ustring.sub(syl, c_i, c_i) local out = c if c ~= "'" and c ~= "." and c ~= "-" then local function peek(dir, count) count = count or 1 local k, si = c_i, s_i while count > 0 do k = k + dir if k < 1 then si = si - 1; if not syllables[si] then return nil end; k = mw.ustring.len(syllables[si]) elseif k > mw.ustring.len(syllables[si]) then si = si + 1; if not syllables[si] then return nil end; k = 1 end local t = mw.ustring.sub(syllables[si], k, k) if t ~= "'" and t ~= "." and t ~= "-" then count = count - 1; if count == 0 then return t end end end end -- 2. DETECT POSITIONS (Ignore ' and .) local is_onset = (mw.ustring.gsub(mw.ustring.sub(syl, 1, c_i-1), "['%.%-]", "") == "") local is_coda = nuc_i and (c_i > nuc_i) local prev, nxt = peek(-1), peek(1) if c == 'u' then if prev == 'o' and (not nxt or nxt == ' ') then out = "ů" end elseif c == 'v' then if is_coda and prev and is_nuc(prev) then local is_u_prev = (prev == 'u' or prev == 'ú') local is_amb_next = (nxt and (nxt=='n' or nxt=='ň' or nxt=='l' or nxt=='ľ' or nxt=='r')) out = (is_u_prev or is_amb_next) and "U" or "ů" else local prev_syl_clean = (s_i > 1) and mw.ustring.gsub(syllables[s_i-1], "['%.%-]", "") or "" local prev_nuc = (s_i > 1) and is_nuc(mw.ustring.sub(prev_syl_clean, -1)) local next_is_vn = (nxt and (nxt == 'n' or nxt == 'ň')) if is_onset and (s_i == 1 or prev_nuc) and next_is_vn then out = "W" else local next_is_z = (nxt == 'z') local after_z = next_is_z and peek(1, 2) -- Peek 2 steps ahead local vz_unv = (next_is_z and after_z and voiceless_paired[after_z]) if vz_unv or (nxt and voiceless_paired[nxt]) then out = "f" elseif nxt and voiced_paired[nxt] and not sonorants[nxt] then out = "w" else out = "v" end end end elseif c == 'f' then if is_coda and nxt and (voiced_paired[nxt] or sonorants[nxt]) then out = "F" end elseif c == 'j' then local prev_is_iy = (prev == 'i' or prev == 'í' or prev == 'y' or prev == 'ý') if is_onset then out = "j" elseif not vowels_set[prev] or prev_is_iy then out = "J" else out = "I" end end end table.insert(res, out) end table.insert(res_syls, table.concat(res)) end return table.concat(res_syls) end function step_final_devoicing(word) local tokens = get_graphemes(word) local i = #tokens while i > 0 do local c = tokens[i] if voiced_paired[c] then tokens[i] = voicing_map[c]; i = i - 1 elseif voiceless_paired[c] then i = i - 1 else break end end return table.concat(tokens) end function generate_all_transcriptions(word, original_word) local gsub = mw.ustring.gsub -- A. Base IPA local base_ipa = ipa_transform_worker(word) -- B. Phonemic local phonemic = gsub(gsub(base_ipa, "ˈ", ""), "[vwFůWU]", "v") phonemic = gsub(gsub(phonemic, "J", "j"), "H", "ɦ") phonemic = gsub(gsub(phonemic, "ä", "æ"), "ľ", "ʎ") phonemic = gsub(phonemic, "I", "j") -- Decode Dental Clusters phonemic = gsub(phonemic, "(%d['%s_]*%d)", function(k) local d1, sep, d2 = mw.ustring.match(k, "(%d)(['%s_]*)(%d)") d1, d2 = tonumber(d1), tonumber(d2) local d1_fix = ((d1+d2)%2==1) and (d1 + (d2%2==0 and 1 or -1)) or d1 return (c1_dec[d1_fix] or "") .. sep .. (c2_dec[d2] or "") end) -- C. Phonetic Base local phonetic_base = resolve_phonetic_base(base_ipa) local roots = { phonetic_base } -- D. Handle "-mo" Variant if IS_MO_VARIANT and original_word then local c = mw.ustring.sub(original_word, -4, -4) -- grab the consonant immediately preceding the ".mo" suffix local c_voiced = voicing_map[c] if c_voiced then local ipa_voiceless = (ipa_map[c] or c) local ipa_voiced = (ipa_map[c_voiced] or c_voiced) local pattern = mw.ustring.gsub(ipa_voiceless, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") .. "mɔ$" -- escape IPA chars for regex and target the end of string local new_root, count = mw.ustring.gsub(phonetic_base, pattern, ipa_voiced .. "mɔ") if count > 0 then table.insert(roots, new_root) end end end -- E. Expand Variants local bases_expanded = {} for _, root in ipairs(roots) do local expansions = expand_variants(root) for _, e in ipairs(expansions) do table.insert(bases_expanded, e) end end -- F. Generate Registers local high_res, low_res = {}, {} for _, ipa in ipairs(bases_expanded) do table.insert(high_res, (gsub(ipa, "æ", "ɛɐ̯"))) local l = gsub(gsub(gsub(ipa, "æ", "e"), "ʎ", "l"), "l ?ˈ?l", "lː") table.insert(low_res, (gsub(l, "n([fvʋ])", "ɱ%1"))) end return { phonemic = phonemic, high = high_res, low = low_res } end -- ============================================================================= -- [[ MAIN EXPORT ]] -- ============================================================================= function export.show(frame) local args = frame:getParent().args local title = mw.title.getCurrentTitle() local t = args["t"] or "" NAMESPACE = title.nsText PAGENAME = (NAMESPACE == "") and title.text or (args["pagename"] or "Pagename not specified") LOAN = mw.ustring.find(t, "loan") and 1 or 0 HARD_SUFFIX = mw.ustring.find(t, "adj") and 1 or 0 AS_IMP = mw.ustring.find(t, "imp") and 1 or 0 IS_MO_VARIANT = false local word = (args["1"] ~= nil) and args["1"] or PAGENAME local original_word = word local manual_hard = (args["1"] ~= nil and mw.ustring.find(args["1"], "[DTNL]")) -- Display Switches local show_rhymes = (args["r"] ~= "0") and not mw.ustring.find(word, "^%-") and not mw.ustring.find(word, "%-$") local show_hyph = (args["h"] ~= "0") local audio = args["a"] or false local audio_accent = args["aa"] or "" -- Pipeline if not manual_hard then word = step_foreign_graphemes(word) end word = step_softening(word) if manual_hard then word = step_foreign_graphemes(word) end word = step_prosody(word) word = step_simplification(word) word = step_assimilation(word) word = step_v_f_j_realization(word) word = step_final_devoicing(word) local final = generate_all_transcriptions(word, original_word) local nuclei, clean_ipa = get_ipa_nuclei(final.phonemic) local out = format_ipa_output(final, frame) if audio then out = out .. "\n*" .. frame:expandTemplate{title="audio", args={"sk", audio, a=audio_accent}} end if show_rhymes then out = out .. format_rhymes(frame, nuclei, clean_ipa) end if show_hyph then out = out .. format_hyphenation(PAGENAME, final.phonemic, frame, original_word, nuclei) end return out end return export p4wcksootvr1sqe6t0yod2ele6evhs5 ထာမ်ပလိက်:sk-IPA/documentation 10 295611 396262 2026-06-03T17:12:24Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|sk-pron}} This template generates the [[Wiktionary:International Phonetic Alphabet|International Phonetic Alphabet]] (IPA) transcription for Slovak entries. It utilizes the [[Module:sk-pron|sk-pron]] module to automatically convert Slovak orthography into phonemic and phonetic transcription. It can also optionally generate rhyme and hyphenation data. It should be placed in the '''..." 396262 wikitext text/x-wiki {{documentation subpage}} {{uses lua|sk-pron}} This template generates the [[Wiktionary:International Phonetic Alphabet|International Phonetic Alphabet]] (IPA) transcription for Slovak entries. It utilizes the [[Module:sk-pron|sk-pron]] module to automatically convert Slovak orthography into phonemic and phonetic transcription. It can also optionally generate rhyme and hyphenation data. It should be placed in the '''Pronunciation''' section as a list item (i.e. place it after the <code>*</code> symbol). '''Note: Entries may currently contain incorrect transcriptions due to limitations in the previous version of the module. A manual revision of existing entries is currently underway to utilize the new system's capabilities.''' == Usage == ; Basic : For the vast majority of Slovak lemmas, use the template with no parameters, this should usually generate the rhymes and hyphenation as well: : {{tl|sk-IPA}} ; Loanwords : For loanwords, where certain (in writing) hard syllables are not pronounced soft and vowels form hiatus rather than diphthongs, specify this: : {{tl|sk-IPA|t=loan}} ; No rhyme : If a word never appears at the end of a sentence/verse (e.g. conjunctions), you may disable the rhyme function: : {{tl|sk-IPA|r=0}} ; Unadapted borrowings, compounds with irregular syllable boundaries, hard endings, etc. : See the following sections for further parameters to use and more examples. == Parameters == ; {{para|1}} (Unnamed) : '''Phonetic Respelling'''. Use this parameter only if the automatic generation is incorrect. This is typically needed for: :* '''Compounds & Prefixes''': Use a dash <code>-</code> to mark morphological boundaries to prevent incorrect assimilation. ::* ''Example:'' {{tl|sk-IPA|päť-slabičný}} for {{m|sk|päťslabičný}} (creates two versions, one without gemination and one with it). :* '''Forced Hard Consonants''': Use capital '''D''', '''T''', '''N''', or '''L''' to force a hard pronunciation before {{m|sk||e}} or {{m|sk||i}} (where they would normally soften). ::* ''Example:'' {{tl|sk-IPA|jeDen}} for {{m|sk|jeden}} (results in {{IPAchar|/jeden/}}, not {{IPAchar|/jeɟen/}}). ::* ''Note:'' Don't use this option for loanwords, where setting {{para|t|loan}} solves this issue. :* '''Adverbs ending in -mo''': A dot <code>.</code> is '''mandatory''' before the suffix to trigger the correct IPA transformation. ::* ''Example:'' {{tl|sk-IPA|obkroč.mo}} for {{m|sk|obkročmo}}. :* '''Foreign diphthongs''': A plus sign <code>+</code> is used to indicate that two vowels (the other one being either ⟨u⟩ or ⟨i⟩) are part of one syllable. ::* ''Example:'' {{tl|sk-IPA|a+uto}} for {{m|sk|auto}}. :* '''Forced Syllable Breaks''': Use <code>.</code> (syllable boundaries) or <code>-</code> (morphological boundaries) to manually indicate syllable boundaries if the hyphenation algorithm fails or to clarify distinct vowels that are not a diphthong. ; {{para|t}} : '''Type (Pronunciation Mode)'''. This parameter alters the generation rules for specific categories of words. Multiple values can be separated by commas (e.g., {{para|t|loan,adj}}). :* <code>loan</code>: '''Loanwords'''. Disables the automatic softening of {{m|sk||de}}, {{m|sk||te}}, {{m|sk||ne}}, {{m|sk||le}} and treats {{m|sk||ia}}, {{m|sk||ie}}, {{m|sk||iu}} as two distinct vowels rather than diphthongs. ::* ''Example:'' {{m|sk|delegácia}} → {{tl|sk-IPA|t{{=}}loan}} :* <code>adj</code>: '''Hard Adjectives'''. Prevents softening of consonants before ''i/e'' in certain adjective endings (e.g., nominative plural {{m|sk|pekní}}). ::* ''Note:'' This is usually added automatically by the "Accelerated Form Creation" gadget, '''remove if it should not be used in case of soft adjectives''' (e.g. {{m|sk|hadí}}). :* <code>imp</code>: '''Imperatives'''. Handles specific assimilation rules for the 1st person plural imperative (e.g., {{m|sk|pečme}}). ::* ''Note:'' This is usually added automatically by the "Accelerated Form Creation" gadget. ; {{para|a}} : '''Audio'''. The filename of an audio recording (without the "File:" prefix). :* ''Example:'' {{tl|sk-IPA|a{{=}}Sk-čučoriedka.ogg}} ; {{para|aa}} : '''Audio accent'''. The accent of the audio recording (if used). :* ''Example:'' {{tl|sk-IPA|a{{=}}Sk-čučoriedka.ogg|aa=Bratislava}} ; {{para|r}} : '''Rhymes'''. Set {{para|r|0}} to hide the rhyme group; rhymes do not generate for affixes by default. :* '''Recommended''': Disable for phrases, clitics or words that cannot appear at the end of a verse (i.e. they are not used to create rhymes). ; {{para|h}} : '''Hyphenation'''. Set {{para|h|0}} to hide the hyphenation points; hyphenation does not generate for affixes and one-syllable words by default. :* '''Recommended''': Disable if there are technical difficulties that can't be easily fixed. == Examples == {| class="wikitable" ! Code !! Output (Approximation) !! Note |- | {{tl|sk-IPA}} || {{IPA|sk|/mat͡ʃka/|[ˈmat͡ʃka]}}<br />{{rhymes|sk|at͡ʃka}}<br />{{hyph|sk|mač|ka}} || Standard usage for {{m|sk|mačka}}. |- | {{tl|sk-IPA|t{{=}}loan}} || {{IPA|sk|/deleɡaːt͡sia/|[ˈdeleɡaːt͡sia]}}<br />{{rhymes|sk|ia}}<br />{{hyph|sk|de|le|gá|ci|a}} || For loanword {{m|sk|delegácia}} (hard ''de'', ''le'', distinct ''ia''). |- | {{tl|sk-IPA|päť-slabičný}} || {{IPA|sk|/pæcslabit͡ʃniː/|[ˈpɛɐ̯cslabit͡ʃniː]<q:high register>|[ˈpɛɐ̯t͡sːlabit͡ʃniː]|[ˈpecslabit͡ʃniː]<q:common>|[ˈpet͡sːlabit͡ʃniː]}}<br />{{rhymes|sk|it͡ʃniː}}<br />{{hyph|sk|päť|sla|bič|ný}} || Creates two forms with and without a dental merger |- | {{tl|sk-IPA|jeDen}} || {{IPA|sk|/jeden/|[ˈjeden]}}<br />{{rhymes|sk|eden}}<br />{{hyph|sk|je|den}} || Capital D forces hard /d/ before e. |- | {{tl|sk-IPA|obkroč.mo}} || {{IPA|sk|/ɔpkrɔt͡ʃmɔ/|[ˈɔpkrɔt͡ʃmɔ]|[ˈɔpkrɔd͡ʒmɔ]}}<br />{{rhymes|sk|ɔt͡ʃmɔ}}<br />{{hyph|sk|ob|kroč|mo}} || Dot triggers special ''-mo'' variant rules. |} <includeonly> {{tcat}} </includeonly> rqgme8s47wjbzk9xinzbvrjxp2986lf 396263 396262 2026-06-03T17:14:35Z 咽頭べさ 33 396263 wikitext text/x-wiki {{documentation subpage}} {{uses lua|sk-pron}} This template generates the [[Wiktionary:International Phonetic Alphabet|International Phonetic Alphabet]] (IPA) transcription for Slovak entries. It utilizes the [[Module:sk-pron|sk-pron]] module to automatically convert Slovak orthography into phonemic and phonetic transcription. It can also optionally generate rhyme and hyphenation data. It should be placed in the '''Pronunciation''' section as a list item (i.e. place it after the <code>*</code> symbol). '''Note: Entries may currently contain incorrect transcriptions due to limitations in the previous version of the module. A manual revision of existing entries is currently underway to utilize the new system's capabilities.''' == Usage == ; Basic : For the vast majority of Slovak lemmas, use the template with no parameters, this should usually generate the rhymes and hyphenation as well: : {{tl|sk-IPA}} ; Loanwords : For loanwords, where certain (in writing) hard syllables are not pronounced soft and vowels form hiatus rather than diphthongs, specify this: : {{tl|sk-IPA|t=loan}} ; No rhyme : If a word never appears at the end of a sentence/verse (e.g. conjunctions), you may disable the rhyme function: : {{tl|sk-IPA|r=0}} ; Unadapted borrowings, compounds with irregular syllable boundaries, hard endings, etc. : See the following sections for further parameters to use and more examples. == Parameters == ; {{para|1}} (Unnamed) : '''Phonetic Respelling'''. Use this parameter only if the automatic generation is incorrect. This is typically needed for: :* '''Compounds & Prefixes''': Use a dash <code>-</code> to mark morphological boundaries to prevent incorrect assimilation. ::* ''Example:'' {{tl|sk-IPA|päť-slabičný}} for {{m|sk|päťslabičný}} (creates two versions, one without gemination and one with it). :* '''Forced Hard Consonants''': Use capital '''D''', '''T''', '''N''', or '''L''' to force a hard pronunciation before {{m|sk||e}} or {{m|sk||i}} (where they would normally soften). ::* ''Example:'' {{tl|sk-IPA|jeDen}} for {{m|sk|jeden}} (results in {{IPAchar|/jeden/}}, not {{IPAchar|/jeɟen/}}). ::* ''Note:'' Don't use this option for loanwords, where setting {{para|t|loan}} solves this issue. :* '''Adverbs ending in -mo''': A dot <code>.</code> is '''mandatory''' before the suffix to trigger the correct IPA transformation. ::* ''Example:'' {{tl|sk-IPA|obkroč.mo}} for {{m|sk|obkročmo}}. :* '''Foreign diphthongs''': A plus sign <code>+</code> is used to indicate that two vowels (the other one being either ⟨u⟩ or ⟨i⟩) are part of one syllable. ::* ''Example:'' {{tl|sk-IPA|a+uto}} for {{m|sk|auto}}. :* '''Forced Syllable Breaks''': Use <code>.</code> (syllable boundaries) or <code>-</code> (morphological boundaries) to manually indicate syllable boundaries if the hyphenation algorithm fails or to clarify distinct vowels that are not a diphthong. ; {{para|t}} : '''Type (Pronunciation Mode)'''. This parameter alters the generation rules for specific categories of words. Multiple values can be separated by commas (e.g., {{para|t|loan,adj}}). :* <code>loan</code>: '''Loanwords'''. Disables the automatic softening of {{m|sk||de}}, {{m|sk||te}}, {{m|sk||ne}}, {{m|sk||le}} and treats {{m|sk||ia}}, {{m|sk||ie}}, {{m|sk||iu}} as two distinct vowels rather than diphthongs. ::* ''Example:'' {{m|sk|delegácia}} → {{tl|sk-IPA|t{{=}}loan}} :* <code>adj</code>: '''Hard Adjectives'''. Prevents softening of consonants before ''i/e'' in certain adjective endings (e.g., nominative plural {{m|sk|pekní}}). ::* ''Note:'' This is usually added automatically by the "Accelerated Form Creation" gadget, '''remove if it should not be used in case of soft adjectives''' (e.g. {{m|sk|hadí}}). :* <code>imp</code>: '''Imperatives'''. Handles specific assimilation rules for the 1st person plural imperative (e.g., {{m|sk|pečme}}). ::* ''Note:'' This is usually added automatically by the "Accelerated Form Creation" gadget. ; {{para|a}} : '''Audio'''. The filename of an audio recording (without the "File:" prefix). :* ''Example:'' {{tl|sk-IPA|a{{=}}Sk-čučoriedka.ogg}} ; {{para|aa}} : '''Audio accent'''. The accent of the audio recording (if used). :* ''Example:'' {{tl|sk-IPA|a{{=}}Sk-čučoriedka.ogg|aa=Bratislava}} ; {{para|r}} : '''Rhymes'''. Set {{para|r|0}} to hide the rhyme group; rhymes do not generate for affixes by default. :* '''Recommended''': Disable for phrases, clitics or words that cannot appear at the end of a verse (i.e. they are not used to create rhymes). ; {{para|h}} : '''Hyphenation'''. Set {{para|h|0}} to hide the hyphenation points; hyphenation does not generate for affixes and one-syllable words by default. :* '''Recommended''': Disable if there are technical difficulties that can't be easily fixed. == Examples == {| class="wikitable" ! Code !! Output (Approximation) !! Note |- | {{tl|sk-IPA}} || {{IPA|sk|/mat͡ʃka/|[ˈmat͡ʃka]}}<br />{{rhymes|sk|at͡ʃka}}<br />{{hyph|sk|mač|ka}} || Standard usage for {{m|sk|mačka}}. |- | {{tl|sk-IPA|t{{=}}loan}} || {{IPA|sk|/deleɡaːt͡sia/|[ˈdeleɡaːt͡sia]}}<br />{{rhymes|sk|ia}}<br />{{hyph|sk|de|le|gá|ci|a}} || For loanword {{m|sk|delegácia}} (hard ''de'', ''le'', distinct ''ia''). |- | {{tl|sk-IPA|päť-slabičný}} || {{IPA|sk|/pæcslabit͡ʃniː/|[ˈpɛɐ̯cslabit͡ʃniː]<q:high register>|[ˈpɛɐ̯t͡sːlabit͡ʃniː]|[ˈpecslabit͡ʃniː]<q:common>|[ˈpet͡sːlabit͡ʃniː]}}<br />{{rhymes|sk|it͡ʃniː}}<br />{{hyph|sk|päť|sla|bič|ný}} || Creates two forms with and without a dental merger |- | {{tl|sk-IPA|jeDen}} || {{IPA|sk|/jeden/|[ˈjeden]}}<br />{{rhymes|sk|eden}}<br />{{hyph|sk|je|den}} || Capital D forces hard /d/ before e. |- | {{tl|sk-IPA|obkroč.mo}} || {{IPA|sk|/ɔpkrɔt͡ʃmɔ/|[ˈɔpkrɔt͡ʃmɔ]|[ˈɔpkrɔd͡ʒmɔ]}}<br />{{rhymes|sk|ɔt͡ʃmɔ}}<br />{{hyph|sk|ob|kroč|mo}} || Dot triggers special ''-mo'' variant rules. |} <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်မပ္တိတ်ရမျာၚ်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်]] </includeonly> 1sq2k4q1a7amocq7myr3kweghcefvi9 ကဏ္ဍ:ထာမ်ပလိက်မပ္တိတ်ရမျာၚ်သလဝ်ဝေန်နဳယျာဂမၠိုၚ် 14 295612 396264 2026-06-03T17:16:01Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ပ္တိတ်ရမျာၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]" 396264 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ပ္တိတ်ရမျာၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]] 65md309yzpo0m6ufirt7mod3g1xija9 ထာမ်ပလိက်:sk-ndecl 10 295613 396265 2026-06-03T17:17:22Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{#invoke:sk-noun|show}}</includeonly><!-- --><noinclude>{{documentation}}</noinclude>" 396265 wikitext text/x-wiki <includeonly>{{#invoke:sk-noun|show}}</includeonly><!-- --><noinclude>{{documentation}}</noinclude> grjvjib0x4xss88i5urp61k2fbns4t2 ထာမ်ပလိက်:sk-ndecl/documentation 10 295614 396266 2026-06-03T17:18:34Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} == Usage == This template returns the whole declension of Slovak nouns. It works with almost any noun or multiword term and requires one mandatory parameter with the option to specify other things as needed. The module that produces the forms for this template is modeled after the official guidelines for Slovak morphology by Jozef Ružička and co.: [https://www.juls.savba.sk/ediela/msj/ ''Mo..." 396266 wikitext text/x-wiki {{documentation subpage}} == Usage == This template returns the whole declension of Slovak nouns. It works with almost any noun or multiword term and requires one mandatory parameter with the option to specify other things as needed. The module that produces the forms for this template is modeled after the official guidelines for Slovak morphology by Jozef Ružička and co.: [https://www.juls.savba.sk/ediela/msj/ ''Morfológia slovenského jazyka'', 1966]. === Parameters === * parameter 1 ''(mandatory)'' – the gender of the noun – the recognised values are <code>m-pr</code> (masculine personal), <code>m-anml</code> (masculine animal), <code>m-in</code> (masculine inanimate), <code>f</code> (feminine) and <code>n</code> (neuter); * parameter 2 ''(only when needed)'' – the genitive form of the noun – use this parameter: ** for any noun ending with ''-er'' or ''-el'', where the ''-e-'' is omitted apart from the basic form (as there are no exact rules as to when the ''e'' is mobile), e.g. {{m|sk|náter}}, {{m|sk|tiger}}; ** if there are more declensions using different stems, e.g. {{m|sk|Herkules}} (use a slash to separate the genitive forms: <code>Herkula/Herkulesa</code>); ** for nouns whose stem changes when declined, e.g. {{m|sk|Zeus}}, {{m|sk|Artemis}}; ** for multiword terms, if some of the words are declined incorrectly by the module, e.g. ''rozliate mlieko''; ** for any nouns, if you are getting wrong forms. === Other optional parameters === * <code>n</code> – the number – for pluralia/singularia tantum – the recognised values are <code>sg</code> and <code>pl</code>; * <code>g</code> – the genitive ending – for specifying the genitive ending of masculine inanimate nouns – the recognised values are <code>u</code>, <code>a/u</code> and <code>u/a</code> (''-a'' is the default ending); * <code>pl</code> – the plural ending – used to specify the plural ending of animate masculine nouns when the module generates an incorrect form – the recognised values are <code>i</code>, <code>ovia</code>, <code>ia</code> and any combination separated by slashes (e.g. <code>i/ovia</code>); * <code>pl2</code> – alternative plural – used when the animate plural is needed along with the inanimate plural for animal nouns (use as <code>pl2=1</code>); * <code>t</code> – type – used in special cases when certain types of verbs are declined differently – the recognised types are these: ** <code>name</code>, <code>surn</code> (surname) – use always with these types; ** <code>loan</code> – use with masculine loanwords ending with ''-ch'' or ''-ta'', masculine inanimate nouns ending with ''-us/-os/-es'' where the ending is eliminated in other cases and feminine or neuter loanwords whose genitive plural should have a short stem and the module is generating a long one; ** <code>dim</code> (diminutive) – use with neuter diminutives ending with ''-ko'' or ''-ce'' if the genitive plural generated by the module is wrong; ** <code>der</code> (derived) – use with feminine derivatives formed with the suffix ''-ba'' ({{m|sk|tvorba}}) or ''-ca'' if the genitive plural generated by the module is wrong; ** <small><code>abstr</code> (abstract), <code>comp-deverb</code> (compound ending with a deverbative noun), <code>material</code>, <code>collect</code> (collective) – better not to use for now, implemented only with potential future use in mind.</small> * any form can be overridden or additional forms added in rare cases where the module can't produce a complete correct declension by using the case and number in this format: <code>gen_sg</code> (genitive singular), <code>dat_pl</code> (dative plural), <code>loc_sg2</code> (the alternative form of the locative singular), etc. === Examples === A simple regular noun like {{m|sk|ruka}} requires only 1 parameter: * {{temp|sk-ndecl|f}} The result: {{sk-ndecl|f|pagename=ruka}} The noun {{m|sk|tiger}} ends with ''-er'', but the ''-e-'' is omitted in other cases, therefore the genitive form must be specified as parameter 2: * {{temp|sk-ndecl|m-anml|tigra}} The result: {{sk-ndecl|m-anml|tigra|pagename=tiger}} The noun {{m|sk|pontifex}} has a different stem for other cases, so genitive must be specified here as well. At the same time, the module produces a wrong nominative plural form, so the ending can be specified as parameter <code>pl</code>: * {{temp|sk-ndecl|m-pr|pontifika|pl=ovia}} The result: {{sk-ndecl|m-pr|pontifika|pl=ovia|pagename=pontifex}} Inanimate masculine nouns often have two possible genitive forms, which can be specified by the parameter <code>g</code>: * {{temp|sk-ndecl|m-in|g=u/a}} The result: {{sk-ndecl|m-in|g=u/a|pagename=trolejbus}} {{m|sk|Kováč}} is a surname, which must be specified by the parameter <code>t</code>: * {{temp|sk-ndecl|m-pr|t=surn}} The result: {{sk-ndecl|m-pr|t=surn|pagename=Kováč}} Pluralia tantum like {{m|sk|Bátorove Kosihy}} need be specified by the parameter <code>n</code>. At the same time, the genitive form must be specified, because in this multiword term, the module can't recognise from the ending alone that the word ''Bátorove'' is an adjective: * {{temp|sk-ndecl|f|n=pl|Bátorových Kosíh}} The result: {{sk-ndecl|f|n=pl|Bátorových Kosíh|pagename=Bátorove Kosihy}} Latin and Greek names often have two declensions – one with the original Latin/Greek genitive stem and one assimilated to the Slovak declension. This can be specified by giving both genitive forms: * {{temp|sk-ndecl|m-pr|Plutóna/Pluta|n=sg}} The result: {{sk-ndecl|m-pr|Plutóna/Pluta|n=sg|pagename=Pluto}} If a multiword term has parts that shouldn't be declined, the genitive must be provided: * {{temp|sk-ndecl|m-in|Síria A|n=sg}} The result: {{sk-ndecl|m-in|Síria A|n=sg|pagename=Sírius A}} == Known issues == There are cases where the module can't handle declining a term even with all the options that it offers. In these cases, use the template {{temp|sk-decl-noun}} instead and fill out the forms manually. These cases are known: * terms containing words connected with a dash, where both of these connected terms are declined; * terms containing words of different genders. == See also == * {{temp|sk-conj}} – for the conjugation of Slovak verbs * {{temp|sk-adecl}} – for the declension of Slovak adjectives <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်|*]] </includeonly> p8911tkw3z4mvkwu0wba9g96noz7hay ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်သလဝ်ဝေန်နဳယျာဂမၠိုၚ် 14 295615 396267 2026-06-03T17:19:40Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]" 396267 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]] azu36cyhts9ui42kjryw8tcyzs23hex ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသလဝ်ဝေန်နဳယျာဂမၠိုၚ် 14 295616 396268 2026-06-03T17:21:09Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]" 396268 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]] 842bq36kqpmro6mhzcoo2z35qd82nww abel-wackets 0 295617 396269 2026-06-03T17:31:17Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "=={{=en=}}== ===နာမ်=== {{en-noun|p}} # {{alternative spelling of|en|able whackets}}" 396269 wikitext text/x-wiki =={{=en=}}== ===နာမ်=== {{en-noun|p}} # {{alternative spelling of|en|able whackets}} h4rfu5c6864zpyj0xheymf4jkk3l8bj မဝ်ဂျူ:sk-noun 828 295618 396270 2026-06-03T17:42:06Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "--[=[ This module contains functions for creating inflection tables for Slovak nouns. ]=]-- local export = {} -- Within this module, declensions are the functions that do the actual -- declension by creating the forms of a basic noun. -- They are defined further down. --local lemma = "Bratislava" local declensions = {} local lang = require("Module:languages").getByCode("sk") local m_table = require("Module:table")..." 396270 Scribunto text/plain --[=[ This module contains functions for creating inflection tables for Slovak nouns. ]=]-- local export = {} -- Within this module, declensions are the functions that do the actual -- declension by creating the forms of a basic noun. -- They are defined further down. --local lemma = "Bratislava" local declensions = {} local lang = require("Module:languages").getByCode("sk") local m_table = require("Module:table") local m_links = require("Module:links") local m_adj = require("Module:sk-adjective") local allowed_genders = { "m-pr", "m-anml", "m-in", "f", "n" } local allowed_genders_set = m_table.listToSet(allowed_genders) local hard_consonants = {"d", "t", "n", "l", "h", "ch", "k", "g"} local soft_consonants = {"ď", "ť", "ň", "ľ", "ž", "š", "č", "dž", "c", "dz", "j"} local ambiguous_consonants = {"b", "m", "p", "r", "s", "v", "z", "f"} local hard_consonants_set = m_table.listToSet(hard_consonants) local soft_consonants_set = m_table.listToSet(soft_consonants) local ambiguous_consonants_set = m_table.listToSet(ambiguous_consonants) local consonants = m_table.append(hard_consonants, soft_consonants, ambiguous_consonants) local consonants_set = m_table.listToSet(consonants) local short_vowels = {"a", "e", "i", "o", "u", "y", "ä", "ö", "ü"} local long_vowels = {"á", "é", "í", "ó", "ú", "ý", "ő", "ű"} local diphthongs = {"ia", "ie", "iu", "ô"} local short_vowels_set = m_table.listToSet(short_vowels) local long_vowels_set = m_table.listToSet(long_vowels) local diphthongs_set = m_table.listToSet(diphthongs) local vowels = m_table.append(short_vowels, long_vowels) local vowels_set = m_table.listToSet(vowels) local obstruents = {"p", "t", "k", "b", "d", "g", "f", "s", "š", "ch", "z", "ž", "č", "dž"} --"v" removed?? local sonorants = {"m", "n", "l", "r", "ʋ", "v"} --"v" added?? local obstruents_set = m_table.listToSet(obstruents) local sonorants_set = m_table.listToSet(sonorants) local bigraphs = {"ch", "dz", "dž"} local bigraphs_set = m_table.listToSet(bigraphs) local prepositions = {"bez", "bezo", "cez", "cezo", "do", "k", "ku", "medzi", "na", "nad", "nado", "o", "do", "okrem", "po", "pod", "podo", "pre", "pred", "predo", "pri", "proti", "naproti", "oproti", "s", "so", "skrz", "u", "v", "vo", "z", "zo", "za"} -- Add more prepositions as needed local prepositions_set = m_table.listToSet(prepositions) local conjunctions = {"a"} -- Add more conjunctions as needed local conjunctions_set = m_table.listToSet(conjunctions) -- The main entry point. -- This is the only function that can be invoked from a template. function export.show(frame) local args = frame:getParent().args NAMESPACE = mw.title.getCurrentTitle().nsText if NAMESPACE == "" then PAGENAME = mw.loadData("Module:headword/data").pagename else if args["pagename"] then PAGENAME = args["pagename"] -- TEST: lemma else error("Pagename not specified") end end GENDER = check_gender(args[1]) NUMBER = args["n"] TYPE = args["t"] GEN_ENDING = args["g"] PLURAL = args["pl"] PLURAL2 = args["pl2"] PRONUNCIATION = args["p"] local genitive = args[2] local category = "" -- Check if PAGENAME is a multiword expression if not mw.ustring.find(PAGENAME, " ") then -- Single-word expression, handle as usual PATTERN = determine_pattern(PAGENAME, genitive) -- Category if NAMESPACE == "" then if PATTERN == "indeclinable" then category = "[[ကဏ္ဍ:နာမ်သလဝ်ဝေန်နဳယျာနကဵုပါ်ပါဲထောံဟွံမာန်ဂမၠိုၚ်|" .. PAGENAME .. "]]" elseif PATTERN == "irregular" then category = "[[ကဏ္ဍ:နာမ်ကိုန်ဨကဝုစ်သလဝ်ဝေန်နဳယျာဂမၠိုၚ်|" .. PAGENAME .. "]]" elseif PATTERN == "adjective" then category = "[[ကဏ္ဍ:နာမ်မဆေၚ်စပ်ကဵုနာမဝိသေသနသလဝ်ဝေန်နဳယျာဂမၠိုၚ်|" .. PAGENAME .. "]]" else category = "[[ကဏ္ဍ:ဝေါဟာသလဝ်ဝေန်နဳယျာမၞုံကဵုဝေါဟာ " .. PATTERN .. " မလဟုတ်စှ်ေဂမၠိုၚ်|" .. PAGENAME .. "]]" end if GENDER == "m-anml" then category = category .. "[[ကဏ္ဍ:ဝေါဟာသလဝ်ဝေန်နဳယျာမၞုံကဵုဝေါဟာ chlap မလဟုတ်စှ်ေဂမၠိုၚ်|" .. PAGENAME .. "]]" end if PAGENAME == "cól" then category = category .. "[[ကဏ္ဍ:ဝေါဟာသလဝ်ဝေန်နဳယျာမၞုံကဵုဝေါဟာ dub မလဟုတ်စှ်ေဂမၠိုၚ်|" .. PAGENAME .. "]]" end end local forms, title -- Find out if there are more genitive stems and if so, process them if genitive then if mw.ustring.find(genitive, "/") then forms, title = decline_with_more_stems(genitive) else forms, title = declensions[PATTERN](PAGENAME, genitive) normalize_forms(forms) end else forms, title = declensions[PATTERN](PAGENAME, genitive) normalize_forms(forms) end specified_by_user(forms, args) return make_table(forms, title) .. category end -- Multiword expressions -- Category if NAMESPACE == "" then category = "[[ကဏ္ဍ:ဝေါဟာသလဝ်ဝေန်နဳယျာမဂၠိုၚ်ကဵုမအရေဝ်ဂမၠိုၚ်|" .. PAGENAME .. "]]" end -- Split into words local units, gen_units = split_into_units(PAGENAME, genitive) -- Process each unit to generate forms local combined_forms = generate_combined_forms(units, gen_units) -- Add forms specified by the user specified_by_user(combined_forms, args) -- Generate the final title and table local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. PAGENAME .. "'' (multiword term)" return make_table(combined_forms, title) .. category end --[=[ Declension functions ]=]-- declensions["chlap"] = function(word, genitive) local forms = {} local syllable_count, syllables = split_into_syllables(word) local mobile_removed = false -- Tracks if a mobile vowel was removed local words_with_mobile = {"kmotor", "švagor", "svokor", "lotor", "obor", "Uhor", "pochábeľ", "väzeň", "učeň", "posol", "diabol", "blázon", "Turek", "fanúšek", "center", "hypochonder", "Kafer", "neger", "gangster", "kapor", "zubor", "bobor", "orol", "pes" } local surn_ech_always_declined = {"Čech", "Plech", "Pech", "Štech", "Vojtech"} -- Determine the stem by removing mobile vowels if applicable local stem = word if (matches_any(word, words_with_mobile) or ends_with_any(word, {"ec", "ček", "íček", "ok"})) and not (TYPE == "surn" and (ends_with_any(word, {"[aeiouyáéíóúýäöüőű]ček", "[aeiouyáéíóúýäöüőű]čok"}) or syllable_count == 1)) and not matches_any(word, {"otrok"}) then stem = remove_mobile_vowel(word) mobile_removed = true -- Mark mobile vowel as removed end -- Adjust specific stems based on predefined mappings stem = ({["švec"] = "ševc", ["žnec"] = "ženc"})[word] or stem -- Remove certain endings for words ending with "us", "os", "es" and "o" if ends_with(word, "[uoea]s") then stem = mw.ustring.sub(word, 1, -3) end if ends_with(word, "o") then stem = remove_last_char(word) end -- Override if a specific argument is given if genitive and NUMBER ~= "pl" then stem = remove_last_char(genitive) if mw.ustring.sub(word, 1, -3) .. get_last_char(word) == remove_last_char(genitive) then mobile_removed = true end end -- Title for the declension table local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("chlap") .. ")" if TYPE == "surn" then if ends_with(word, "a[iy]") then title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("chlap") .. " or " .. pattern_link("kuli") .. ")" elseif ends_with_any(word, {"ých", "ech"}) and not matches_any(word, surn_ech_always_declined) then title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("chlap") .. " or indeclinable)" end end -- Helper variables for analyzing the last and penultimate characters local ultimate, penultimate = get_last_letters(stem) local first = get_first_char(word) -- Determine alternative dative and locative for some nouns if matches_any(word, {"človek", "pán", "čert", "diabol", "vlk", "pes", "Boh", "boh", "otec", "syn", "duch", "Kristus", "don", "šor"}) then set_forms(forms, {"dat_sg2", "loc_sg2"}, {stem .. "u", stem .. "u"}) end local nom_pl = "i" if PLURAL then if mw.ustring.find(PLURAL, "/") then local endings = {} for part in mw.ustring.gmatch(PLURAL, "[^/]+") do table.insert(endings, part) end nom_pl = endings[1] for i = 2, 4 do if endings[i] then set_forms(forms, {"nom_pl" .. i}, {append_ending(stem, endings[i])}) else break end end else nom_pl = PLURAL end elseif (ends_with_any(word, {"fil", "fób", "graf", "nóm"}) and not matches_any(word, {"xylograf", "typograf"})) or matches_any(word, {"cynik", "epik", "klasik", "stoik", "Brit", "Búr", "Gal", "Ír", "Dór", "Italik", "Ión", "Nór", "cár", "lodivod", "odkundes", "starík", "muž", "svat", "apoštol", "augur", "bán", "bogomil", "buržuj", "don", "druid", "eféb", "famulus", "héros", "man", "posol" }) then set_forms(forms, {"nom_pl2"}, {append_ending(stem, "ovia")}) elseif (ends_with_any(word, {"[^c]h", "g", "ček", "ek", "ik", "čik", "ok", "o", "duch"}) and word ~= "pes") or matches_any(word, {"otec", "syn", "ujec", "strýc", "svák", "svokor", "tesť", "švagor", "zať", "kmotor", "ded", "kmeť", "pobratim", "otčim", "zlosyn", "princ", "Bask", "Frank", "Ind", "Ink", "Kurd", "Dák", "Čudo", "Fríz", "Azték", "Asýr", "Etrusk", "Kazach", "Kašub", "odľud", "člen", "zved", "hňup", "cicerone"}) or (ends_with(word, "ch") and TYPE == "loan") or (ends_with_any(word, {"us", "es"}) and genitive ~= word .. "a") or matches_any(TYPE, {"comp-deverb", "surn", "name"}) or PLURAL == "ovia" then nom_pl = "ovia" if TYPE == "surn" then append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom", stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami") end elseif ends_with(word, "teľ") or (ends_with(word, "an") and is_capital(first)) or matches_any(word, {"občan", "dedinčan", "mešťan", "zeman", "ostrovan", "krajan", "dolňan", "horňan", "južan", "severan", "rodič", "dedič", "brat", "hosť", "manžel", "exmanžel", "sused", "žid", "Žid", "kresťan", "nekresťan", "pohan"}) then nom_pl = "ia" if word == "pohan" then set_forms(forms, {"nom_pl2"}, {append_ending(stem, "i")}) end end -- Determine instrumental plural ending local ins_pl = "mi" -- Default instrumental plural ending is "mi" if ultimate == "m" or mobile_removed or ends_with_any(word, {"o", "ius"}) or matches_any(word, {"hosť", "tesť", "Kopt"}) --obstruents_set[penultimate] and obstruents_set[ultimate] then ins_pl = "ami" end -- Populate forms table with singular and plural endings append_endings(forms, word, stem, "a", "ovi", "a", "ovi", "om", nom_pl, append_ending(stem, "ov"), "om", "ov", "och", ins_pl ) -- Surnames ending with -ých, -ech, -ai, -ay if TYPE == "surn" then if ends_with_any(word, {"ých", "ech"}) and not matches_any(word, surn_ech_always_declined) then append_alternative_singular(forms, word, word, word, word, word) append_alternative_plural(forms, word, word, word, word, word, word) elseif ends_with(word, "a[iy]") then append_alternative_singular(forms, word .. "ho", word .. "mu", word .. "ho", word .. "m", word .. "m") set_forms(forms, {"ins_pl2"}, {word .. "ami"}) end end -- Exceptions if word == "človek" then set_forms(forms, {"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"}, {"ľudia", "ľudí", "ľuďom", "ľudí", "ľuďoch", "ľuďmi"} ) elseif word == "héros" then set_forms(forms, {"gen_sg", "dat_sg", "acc_sg", "loc_sg", "ins_sg", "nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl", "gen_sg2", "dat_sg2", "acc_sg2", "loc_sg2", "ins_sg2", "nom_pl2", "gen_pl2", "dat_pl2", "acc_pl2", "loc_pl2", "ins_pl2"}, {"hérosa", "hérosovi", "hérosa", "hérosovi", "hérosom", "hérosi", "hérosov", "hérosom", "hérosov", "hérosoch", "hérosmi", "héroa", "héroovi", "héroa", "héroovi", "héroom", "héroovia", "héroov", "héroom", "héroov", "hérooch", "héroami"} ) end -- Vocative if matches_any(word, {"syn", "sváko", "švagor", "kmotor", "brat", "synko", "synáčik", "pán", "chlapec", "priateľ", "majster", "Boh", "boh", "Pán", "Syn", "Duch", "Ježiš", "Ježiško", "Kristus", "Spasiteľ", "Vykupiteľ", "Stvoriteľ", "Premožiteľ", "Kráľ", "Hospodin", "baránok", "Baránok", "tešiteľ", "Tešiteľ", "hriešnik", "protivník", "kresťan", "otec", "Otec", "chlap", "človek"}) then voc_stem = stem if word == "synáčik" then voc_stem = "synáčk" end if word == "pán" then voc_stem = "pan" end if word == "Pán" then voc_stem = "Pan" end if ends_with_any(word, {"teľ", "o"}) or matches_any(word, {"syn", "Syn", "Duch", "Ježiš", "Kráľ", "hriešnik", "synáčik", "baránok", "Baránok"}) then set_forms(forms, {"voc_sg"}, {append_ending(voc_stem, "u")}) else if ends_with_any(voc_stem, {"k", "c"}) then voc_stem = remove_last_char(voc_stem) .. "č" elseif ends_with(voc_stem, "h") then voc_stem = remove_last_char(voc_stem) .. "ž" end set_forms(forms, {"voc_sg"}, {append_ending(voc_stem, "e")}) end if not matches_any(word, {"človek", "pán", "brat"}) then set_forms(forms, {"voc_sg2"}, {word}) elseif word == "brat" then set_forms(forms, {"voc_sg2", "voc_sg3"}, {"bratu", "brat"}) end end return forms, title -- Return forms table and title for declension end declensions["hrdina"] = function(word, genitive) local forms = {} local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("hrdina") .. ")" local stem = remove_suffix(word, "a") if ends_with(word, "[oeě]") then stem = remove_last_char(word) if ends_with(word, "ě") and ends_with(stem, "[dtnl]") then stem = soften_last_consonant(stem) end end local nom_pl_ending = "ovia" if ends_with_any(word, {"ista", "ita"}) or (ends_with(word, "ta") and TYPE == "loan") then nom_pl_ending = "i" end local ins_pl_ending = "ami" if ends_with(word, "[aeiouyáéíóúýäöüőű]ta") and TYPE == "loan" then ins_pl_ending = "mi" end append_endings(forms, word, stem, "u", "ovi", "u", "ovi", "om", nom_pl_ending, stem .. "ov", "om", "ov", "och", ins_pl_ending ) if TYPE == "surn" then append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom", stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami") end if word == "buržoa" then set_forms(forms, {"dat_sg", "loc_sg", "ins_sg", "nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl"}, {"buržuovi", "buržuovi", "buržuom", "buržuovia", "buržuov", "buržuom", "buržuov", "buržuoch"} ) end return forms, title end declensions["kuli"] = function(word, genitive) local forms = {} local stem = word local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("kuli") .. ")" append_endings(forms, word, stem, "ho", "mu", "ho", "m", "m", "ovia", stem .. "ov", "om", "ov", "och", "ami" ) if TYPE == "surn" then append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom", stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami") end return forms, title end declensions["dub"] = function(word, genitive) local forms = {} local mobile_removed = false -- Tracks if a mobile vowel was removed local words_with_mobile = {"priemysel", "počet", "ocot", "bahor", "chrbát", "ker", "cukor", "uhor", "vietor", "víchor", "vôdor", "kotol", "kapor", "zubor", "bobor", "orol", "pes", "mozog", "uhol"} local syllable_count, syllables = split_into_syllables(word) -- Determine the stem by removing mobile vowels if applicable local stem = word if (matches_any(word, words_with_mobile) or (ends_with_any(word, {"íček", "ýček", "ok"}) and syllable_count ~= 1)) and not matches_any(word, {"polrok", "nárok", "zákrok", "rozkrok"}) then stem = remove_mobile_vowel(word) mobile_removed = true -- Mark mobile vowel as removed end -- Adjust specific stems based on predefined mappings stem = ({["mráz"] = "mraz", ["vietor"] = "vetr", ["kôl"] = "kol", ["stôl"] = "stol", ["vôl"] = "vol", ["chlieb"] = "chleb", ["ensemble"] = "ensembl"})[word] or stem -- Remove certain endings for words ending with "us", "os", "es" and "o" if (ends_with(word, "[uoe]s") and TYPE == "loan") or ends_with(word, "izmus") then stem = mw.ustring.sub(word, 1, -3) end if ends_with(word, "o") then stem = remove_last_char(word) end -- Pluralia tantum if NUMBER == "pl" then stem = remove_suffix(word, "y") end -- Override if a specific argument is given if genitive and NUMBER ~= "pl" then stem = remove_last_char(genitive) if stem == remove_last_char(remove_last_char(word)) .. get_last_char(word) then mobile_removed = true elseif stem == word then mobile_removed = false end end -- Set "mobile_removed" if genitive was set by the user if ends_with(word, "e[lr]") and ends_with(stem, "[^e][lr]") then mobile_removed = true end -- Title for the declension table local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("dub") .. ")" if GENDER == "m-anml" then if matches_any(word, {"vták", "vlk", "pes"}) then title = "Declension of ''" .. word .. "'' <br>(patterns " .. pattern_link("chlap") .. " <small>(singular, plural 1)</small> and " .. pattern_link("dub") .. " <small>(plural 2)</small>)" elseif PLURAL2 then title = "Declension of ''" .. word .. "'' <br>(patterns " .. pattern_link("chlap") .. " <small>(singular, plural 2)</small> and " .. pattern_link("dub") .. " <small>(plural 1)</small>)" else title = "Declension of ''" .. word .. "'' <br>(patterns " .. pattern_link("chlap") .. " <small>(singular)</small> and " .. pattern_link("dub") .. " <small>(plural)</small>)" end end -- Helper variables for analyzing the last and penultimate characters local ultimate, penultimate = get_last_letters(stem) local first = get_first_char(word) -- Determine genitive singular ending local gen_sg = "a" if (matches_any(TYPE, {"abstr", "comp-deverb", "material", "collect", "loan"}) or matches_any(GEN_ENDING, {"u", "u/a"}) or ends_with_any(word, {"izmus", "x"}) or (ends_with(word, "m") and not is_capital(first)) or (ends_with(word, "z") and is_capital(first))) and not matches_any(GEN_ENDING, {"a", "a/u"}) then gen_sg = "u" end -- Override genitive singular ending if a specific argument is given if genitive then gen_sg = get_last_char(genitive) end -- Determine locative singular ending based on specific suffixes and patterns local loc_sg = "e" if ends_with_any(word, {"k", "g", "h", "ch"}) or (ends_with(word, "i[ue]s") and TYPE == "loan") then loc_sg = "u" elseif (ends_with(word, "ér") or (ends_with(word, "ál") and not matches_any(word, {"bál", "paškál", "paušál", "šál", "škandál", "žurnál"})) or matches_any(word, {"Alžír", "klavír", "apríl", "jún", "júl"})) then loc_sg = "i" end -- Determine genitive plural ending local gen_pl = stem .. "ov" -- Default genitive plural ending is "ov" -- Adjust genitive plural for specific place names and patterns if is_capital(first) and (ends_with_any(word, {"any", "íky", "áky", "iaky"}) or matches_any(word, {"Krompachy", "Kubachy", "Veľbachy", "Spišské Vlachy", "Žabokreky", "Čechy", "Brezolupy", "Bruty", "Rakoľuby", "Rakúsy", "Prusy", "Veľaty", "Piešťany", "Bieščary"})) then local gen_stem = remove_last_char(word) -- Remove last character to get the base stem local syllable_count, syllables = split_into_syllables(gen_stem) local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" -- Lengthen the vowel if the penultimate syllable is short, otherwise use unchanged stem if is_long(penultimate_syllable) then gen_pl = gen_stem else gen_pl = remove_suffix(gen_stem, last_syllable) .. lengthen_vowel(last_syllable) end end -- Special cases for genitive plural of specific words if word == "čas" then gen_pl = "čias" elseif word == "raz" then gen_pl = "ráz" end -- Determine instrumental plural ending local ins_pl = "mi" -- Default instrumental plural ending is "mi" if ultimate == "m" or mobile_removed or ends_with_any(word, {"o", "ius", "eus"}) or (penultimate == "m" and consonants_set[ultimate]) then ins_pl = "ami" end -- Doublets for instrumental plural if matches_any(word, {"schod", "schody", "fúz", "fúzy", "roh", "rohy", "paroh", "parohy", "čary", "orech"}) then set_forms(forms, {"ins_pl2"}, {stem .. "ami"}) elseif matches_any(word, {"zub", "dol", "most", "prst", "piest", "necht"}) then ins_pl = "ami" set_forms(forms, {"ins_pl2"}, {stem .. "mi"}) end -- Populate forms table with singular and plural endings append_endings(forms, word, stem, gen_sg, "u", nil, loc_sg, "om", "y", gen_pl, "om", nil, "och", ins_pl ) -- Alternative genitive ending if GEN_ENDING == "a/u" then set_forms(forms, {"gen_sg2"}, {stem .. "u"}) elseif GEN_ENDING == "u/a" then set_forms(forms, {"gen_sg2"}, {stem .. "a"}) end -- Exceptions if matches_any(word, {"sen", "dol"}) then set_forms(forms, {"loc_pl2"}, {stem .. "ách"}) elseif word == "čas" then set_forms(forms, {"gen_pl2"}, {"časov"}) end -- Animal nouns if GENDER == "m-anml" then append_animal_singular(forms, stem) if matches_any(word, {"vták", "vlk", "pes"}) or PLURAL2 then local forms2, title2 = declensions["chlap"](word, stem .. gen_sg) append_second_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"], forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"]) if matches_any(word, {"vták", "vlk", "pes"}) then switch_plural_forms(forms) --changes the prefered forms -- Determine alternative dative and locative for some nouns if matches_any(word, {"vlk", "pes"}) then set_forms(forms, {"dat_sg2", "loc_sg2"}, {stem .. "u", stem .. "u"}) end end end end return forms, title -- Return forms table and title for declension end declensions["stroj"] = function(word, genitive) local forms = {} local mobile_removed = false -- Tracks if a mobile vowel was removed local words_with_no_mobile = {"kúpeľ", "červeň", "kameň", "jačmeň", "koreň", "prameň", "prsteň", "jeleň"} local first = get_first_char(word) -- Determine the stem by removing mobile vowels if applicable local stem = word if (ends_with_any(word, {"ec", "iec", "[^ti]eľ", "oľ", "[^i]eň", "eť", "[^i]er", "el"}) or (ends_with(word, "ac") and (is_capital(first) or word == "desaterac"))) and not matches_any(word, words_with_no_mobile) then stem = remove_mobile_vowel(word) mobile_removed = true -- Mark mobile vowel as removed end -- Adjust specific stems based on predefined mappings stem = ({["dážď"] = "dažď", ["kôš"] = "koš", ["nôž"] = "nož", ["kôň"] = "koň", ["timbre"] = "timbr"})[word] or stem -- Pluralia tantum if NUMBER == "pl" then stem = remove_suffix(word, "e") end -- Override if a specific argument is given if genitive and NUMBER ~= "pl" then stem = remove_last_char(genitive) if stem == remove_last_char(remove_last_char(word)) .. get_last_char(word) then mobile_removed = true elseif stem == word then mobile_removed = false end end -- Set "mobile_removed" if genitive was set by the user if ends_with(word, "e[lr]") and ends_with(stem, "[^e][lr]") then mobile_removed = true end -- Title for the declension table local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("stroj") .. ")" if GENDER == "m-anml" then if PLURAL2 then title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(patterns " .. pattern_link("chlap") .. " <small>(singular, plural 2)</small> and " .. pattern_link("stroj") .. " <small>(plural 1)</small>)" else title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(patterns " .. pattern_link("chlap") .. " <small>(singular)</small> and " .. pattern_link("stroj") .. " <small>(plural)</small>)" end elseif word == "cól" then title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("stroj") .. " or " .. pattern_link("dub") .. ")" end -- Helper variables for analyzing the last and penultimate characters local ultimate, penultimate = get_last_letters(stem) local first = get_first_char(word) -- Determine genitive singular ending local gen_sg = "a" if ((matches_any(TYPE, {"abstr", "material"}) or matches_any(GEN_ENDING, {"u", "u/a"})) and not matches_any(word, {"jačmeň", "kameň", "olej", "loj", "vývoj", "rozvoj"})) and not matches_any(GEN_ENDING, {"a", "a/u"}) then gen_sg = "u" end -- Override genitive singular ending if a specific argument is given if genitive then gen_sg = get_last_char(genitive) end -- Determine genitive plural ending local gen_pl = stem .. "ov" -- Default genitive plural ending is "ov" -- Adjust genitive plural for specific place names and patterns if is_capital(first) and (ends_with_any(word, {"áre", "iare"}) or word == "Tlmače") then local gen_stem = remove_last_char(word) -- Remove last character to get the base stem local syllable_count, syllables = split_into_syllables(gen_stem) local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" -- Lengthen the vowel if the penultimate syllable is short, otherwise use unchanged stem if is_long(penultimate_syllable) then gen_pl = gen_stem else gen_pl = remove_suffix(gen_stem, last_syllable) .. lengthen_vowel(last_syllable) end end -- Special cases for genitive plural of specific words if word == "Ladce" then gen_pl = "Ladiec" elseif word == "Vráble" then gen_pl = "Vrábeľ" elseif word == "peniaze" then gen_pl = "peňazí" elseif matches_any(word, {"deň", "kôň", "groš"}) then gen_pl = append_ending(stem, "í") end -- Determine instrumental plural ending local ins_pl = "mi" -- Default instrumental plural ending is "mi" if mobile_removed or (obstruents_set[penultimate] and obstruents_set[ultimate]) then ins_pl = "ami" end -- Populate forms table with singular and plural endings append_endings(forms, word, stem, gen_sg, "u", nil, "i", "om", "e", gen_pl, "om", nil, "och", ins_pl ) -- Alternative genitive ending if GEN_ENDING == "a/u" then set_forms(forms, {"gen_sg2"}, {stem .. "u"}) elseif GEN_ENDING == "u/a" then set_forms(forms, {"gen_sg2"}, {stem .. "a"}) end -- Exceptions if matches_any(word, {"deň", "poldeň"}) then set_forms(forms, {"nom_pl", "acc_pl", "loc_sg2"}, {append_ending(stem, "i"), append_ending(stem, "i"), append_ending(stem, "e")} ) elseif word == "ďateľ" then set_forms(forms, {"gen_sg2", "dat_sg2", "loc_sg2", "ins_sg2", "nom_pl2", "gen_pl2", "dat_pl2", "acc_pl2", "loc_pl2", "ins_pl2"}, {"ďatľa", "ďatľovi", "ďatľovi", "ďatľom", "ďatle", "ďatľov", "ďatľom", "ďatle", "ďatľoch", "ďatľami"} ) elseif word == "cól" then set_forms(forms, {"loc_sg2", "nom_pl2", "acc_pl2"}, {"cóle", "cóly", "cóly"} ) end -- Animal nouns if GENDER == "m-anml" then append_animal_singular(forms, stem) if PLURAL2 then local forms2, title2 = declensions["chlap"](word, stem .. gen_sg) append_second_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"], forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"]) end end return forms, title -- Return forms table and title for declension end declensions["žena"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "a") local title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("žena") .. ")" if ends_with(word, "ea") then title = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. word .. "'' <br>(pattern " .. pattern_link("žena") .. ", loanword ending with ''-ea'')" end -- Pluralia tantum or genitive if NUMBER == "pl" then stem = remove_suffix(word, "y") end if genitive and NUMBER ~= "pl" then stem = remove_suffix(genitive, "y") end -- Split into syllables local gen_pl = "" local syllable_count, syllables = split_into_syllables(stem) local word_syllable_count, word_syllables = split_into_syllables(word) -- Get the last and second-to-last syllables for rule checks local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" local word_penultimate_syllable = word_syllables[2] or "" local ultimate, penultimate = get_last_letters(stem) -- 1. Add a vowel between the last two consonants of a cluster at the end of the stem if ends_with_consonant_cluster(last_syllable) or word_syllable_count == 1 then if (ultimate == "k" and not matches_any(word, {"banka"})) or (ultimate == "b" and (TYPE == "der" or not sonorants_set[penultimate])) or sonorants_set[ultimate] or matches_any(word, {"farba", "karta", "buchta", "astma"}) or (obstruents_set[penultimate] and ultimate == "v") then if penultimate ~= "j" and (word_syllable_count == 1 or is_short(word_penultimate_syllable)) then gen_pl = harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate if matches_any(word, {"handra", "perla", "metla", "slivka", "tehla", "vidly", "karta", "kvapka", "stovka", "doska"}) then gen_pl = remove_suffix(stem, ultimate) .. "á" .. ultimate set_forms(forms, {"gen_pl2"}, {harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate}) end if matches_any(word, {"jamka", "kvapka"}) then set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, ultimate) .. "ô" .. ultimate}) end if matches_any(word, {"astma"}) then set_forms(forms, {"gen_pl2"}, {stem .. "í"}) end elseif obstruents_set[ultimate] and (is_long(word_penultimate_syllable) or penultimate == "j") then gen_pl = remove_suffix(stem, ultimate) .. "o" .. ultimate elseif (sonorants_set[ultimate] or ultimate == "v") and (is_long(word_penultimate_syllable) or penultimate == "j") then gen_pl = remove_suffix(stem, ultimate) .. "e" .. ultimate if penultimate ~= "j" then set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, ultimate) .. "ie" .. ultimate}) end end end end -- 2. Add "í" if stem ends with a vowel or a soft consonant if gen_pl == "" and (vowels_set[ultimate] or matches_any(word, {"medaila", "pera", "kanva", "panva", "skepsa", "nuansa"})) then gen_pl = stem .. "í" if matches_any(word, {"nuansa"}) then set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)}) end end -- 3. Return the stem with no change if conditions match if gen_pl == "" and (is_long(penultimate_syllable) or ends_with_any(stem, {"tvor", "ov"}) or mw.ustring.match(last_syllable, "[Jj][eo]") or (TYPE == "loan" and matches_any(get_vowel(last_syllable), {"e", "o"}))) then gen_pl = stem end -- 4. Logic to use the lengthened vowel if conditions match if gen_pl == "" and (not (ends_with_consonant_cluster(last_syllable) or vowels_set[ultimate]) or (ends_with_consonant_cluster(last_syllable) and sonorants_set[penultimate] and obstruents_set[ultimate]) or (ends_with_consonant_cluster(last_syllable) and matches_any(penultimate, {"c", "s", "z", "š", "ž", "p"}) and matches_any(ultimate, {"t", "d"}))) and not matches_any(word, {"šachta", "mzda"}) then gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable) if mw.ustring.find(stem, "au[bcčdďfghjklľmnňpqrsštťvwxzž]$") then gen_pl = remove_suffix(stem, "a" .. last_syllable) .. "á" .. last_syllable end end -- 5. long -á- instead of -ia- for some loanwords if matches_any(word, {"pyžama", "šachta"}) then gen_pl = (word == "pyžama") and "pyžám" or "šácht" if word == "šachta" then set_forms(forms, {"gen_pl2"}, {"šachiet"}) end end -- 6. Exceptions if word == "mzda" then gen_pl = "miezd" end if gen_pl == "" then gen_pl = stem end local dat_pl, loc_pl if is_long(word_penultimate_syllable) then dat_pl, loc_pl = "am", "ach" else dat_pl, loc_pl = "ám", "ách" end local dat_sg, loc_sg if ultimate == "e" then dat_sg, loc_sg = "i", "i" else dat_sg, loc_sg = "e", "e" end append_endings(forms, word, stem, "y", dat_sg, "u", loc_sg, "ou", "y", gen_pl, dat_pl, nil, loc_pl, "ami" ) if matches_any(word, {"zora", "žiara", "žiabra"}) then set_forms(forms, {"nom_pl", "acc_pl"}, {stem .. "e", stem .. "e"} ) end return forms, title end declensions["gazdiná"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "á") local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("gazdiná") .. ")" local syllable_count, syllables = split_into_syllables(stem) local last_syllable = syllables[1] local gen_pl = "" if ends_with_consonant_cluster(last_syllable) then gen_pl = mw.ustring.sub(stem, 1, -2) .. "ien" else gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable) end append_endings(forms, word, stem, "ej", "ej", "ú", "ej", "ou", "é", gen_pl, "ám", nil, "ách", "ami" ) return forms, title end declensions["ulica"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "a") local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("ulica") .. ")" -- Pluralia tantum if NUMBER == "pl" then stem = remove_suffix(word, "e") if ends_with_any(stem, {"d", "t", "n", "l"}) then stem = soften_last_consonant(stem) end end -- Split into syllables local gen_pl = "" local syllable_count, syllables = split_into_syllables(stem) local word_syllable_count, word_syllables = split_into_syllables(word) -- Get the last and second-to-last syllables for rule checks local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" local word_penultimate_syllable = word_syllables[2] or "" local ultimate, penultimate = get_last_letters(stem) local first = get_first_char(word) -- 1. Add a vowel between the last two consonants of a cluster at the end of the stem if ends_with_consonant_cluster(last_syllable) then if (is_capital(first) and ends_with(word, "ce")) or matches_any(word, {"dverce", "ovca", "fakľa", "drumbľa", "husle", "jasle", "kachle", "hrable", "šabľa", "mašľa", "žemľa", "ríbezľa", "čerešňa", "sukňa", "višňa"}) then gen_pl = harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate if matches_any(word, {"drumbľa", "husle", "jasle", "kachle", "hrable", "šabľa", "mašľa", "žemľa", "ríbezľa", "čerešňa", "sukňa", "višňa"}) then set_forms(forms, {"gen_pl2"}, {append_ending(stem, "í")}) end end end -- 2. Add "í" if stem ends with a vowel or a soft consonant if gen_pl == "" and (matches_any(ultimate, {"dz", "dž", "ž", "ť", "ď", "j", "i", "y"}) or ends_with_any(word, {"nca", "oľa", "ôľa", "aľa", "ša", "ča"}) or matches_any(word, {"liace", "pasca", "páľa", "trúbeľa", "mrľa", "konope", "večera", "rozopra"}) or (matches_any(ultimate, {"ľ"}) and consonants_set[penultimate]) or (matches_any(ultimate, {"ň"}) and penultimate ~= "y")) and not matches_any(word, {"papuča", "priča", "hrča", "paprča", "garniža", "fakľa", "skriňa", "sviňa", "abatiša", "čaša", "fľaša", "Krkonoše", "ríša", "skrýša"}) then gen_pl = append_ending(stem, "í") end -- 3. Logic to use the lengthened vowel if conditions match if gen_pl == "" and not ends_with_consonant_cluster(last_syllable) and not vowels_set[ultimate] and ((ends_with(word, "ca") and TYPE ~= "der") or ends_with_any(word, {"yňa", "uľa"}) or matches_any(word, {"papuča", "priča", "hrča", "chvíľa", "míľa", "košeľa", "nedeľa", "guľa", "hoľa", "homoľa", "skriňa", "sviňa", "abatiša", "čaša", "fľaša", "Krkonoše", "ríša", "skrýša", "garniža", "Hybe", "dvere", "kuša", "moruša"})) then if is_long(penultimate_syllable) then gen_pl = stem else gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable) if matches_any(word, {"homoľa", "kuša", "moruša", "hrča", "paprča", "guľa", "hoľa"}) then set_forms(forms, {"gen_pl2"}, {append_ending(stem, "í")}) end end end if gen_pl == "" then gen_pl = stem end local dat_pl, loc_pl if ends_with_any(stem, {"i", "y"}) or word == "pizza" then dat_pl, loc_pl = "ám", "ách" elseif is_long(word_penultimate_syllable) or ends_with(stem, "j") then dat_pl, loc_pl = "am", "ach" else dat_pl, loc_pl = "iam", "iach" end append_endings(forms, word, stem, "e", "i", "u", "i", "ou", "e", gen_pl, dat_pl, nil, loc_pl, "ami" ) if word == "rozopra" then set_forms(forms, {"dat_pl2", "loc_pl2"}, {"rozoprám", "rozoprách"} ) elseif word == "dvere" then set_forms(forms, {"dat_pl", "loc_pl", "gen_pl2", "ins_pl2"}, {"dverám", "dverách", "dverí", "dvermi"} ) end return forms, title end declensions["irregular"] = function(word, genitive) local forms = {} local title = "Declension of ''" .. word .. "'' (irregular)" if matches_any(word, {"mať", "mater", "mati"}) then local stem = "mater" append_endings(forms, word, stem, "e", "i", "", "i", "ou", "e", stem .. "í", "iam", "e", "iach", "ami" ) local accusative = (word == "mater") and {"mater", "mať"} or {"mať", "mater"} set_forms(forms, {"acc_sg", "acc_sg2"}, accusative) elseif ends_with(word, "pani") then local stem = remove_suffix(word, "ni") .. "ň" append_endings(forms, word, stem, "ej", "ej", "iu", "ej", "ou", "ie", stem .. "í", "iam", nil, "iach", "iami" ) end return forms, title end declensions["dlaň"] = function(word, genitive) local forms = {} local words_with_mobile_vowel = {"faloš", "osuheľ", "siheľ", "myseľ"} local stem if genitive then stem = remove_suffix(genitive, "e") elseif matches_any(word, words_with_mobile_vowel) or ends_with(word, "eň") then stem = remove_mobile_vowel(word) else stem = word end local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("dlaň") .. ")" local syllable_count, syllables = split_into_syllables(word) local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" local last_char = get_last_char(word) local dat_pl, loc_pl if is_long(penultimate_syllable) or last_char == "j" then dat_pl, loc_pl = "am", "ach" elseif word == "kader" then dat_pl, loc_pl = "ám", "ách" else dat_pl, loc_pl = "iam", "iach" end append_endings(forms, word, stem, "e", "i", nil, "i", "ou", "e", append_ending(stem, "í"), dat_pl, nil, loc_pl, "ami" ) if matches_any(word, {"myseľ", "tvár", "hneď", "raž"}) then set_forms(forms, {"gen_sg2"}, {append_ending(stem, "i")}) end return forms, title end declensions["kosť"] = function(word, genitive) local forms = {} local words_with_mobile_vowel = {"voš", "lož", "Ves", "ves", "cirkev", "reďkev"} local stem = (matches_any(word, words_with_mobile_vowel)) and remove_mobile_vowel(word) or word if word == "česť" then stem = "cť" end local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("kosť") .. ")" append_endings(forms, word, stem, "i", "i", nil, "i", "ou", "i", append_ending(stem, "í"), "iam", nil, "iach", "ami" ) if word == "hrsť" then set_forms(forms, {"nom_pl", "acc_pl"}, {"hrste", "hrste"} ) elseif word == "lesť" then append_alternative_singular(forms, "ľsti", "ľsti", nil, "ľsti", "ľsťou") append_alternative_plural(forms, "ľsti", "ľstí", "ľstiam", nil, "ľstiach", "ľsťami") elseif matches_any(word, {"cirkev", "reďkev"}) then set_forms(forms, {"dat_pl", "loc_pl"}, {stem .. "ám", stem .. "ách"} ) end return forms, title end declensions["mesto"] = function(word, genitive) local forms = {} local ultimate, penultimate = get_last_letters(word) local special_type = "" local stem = remove_suffix(word, "o") if penultimate == "u" and ultimate == "m" then stem = remove_suffix(word, "um") special_type = ", of Latin origin ending with ''-um''" elseif penultimate == "o" and ultimate == "n" then stem = remove_suffix(word, "on") special_type = ", of Greek origin ending with ''-on''" elseif penultimate == "m" and ultimate == "ä" then stem = remove_suffix(word, "ä") .. "en" special_type = ", archaic type ending with ''-mä''" end -- Pluralia tantum if NUMBER == "pl" then stem = remove_suffix(word, ultimate) end local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("mesto") .. special_type .. ")" local stem_ultimate, stem_penultimate = get_last_letters(stem) local loc_sg = "e" if vowels_set[stem_ultimate] or matches_any(stem_ultimate, {"k", "g", "ch", "h"}) then loc_sg = "u" elseif matches_any(word, {"vnútro", "nebo"}) then loc_sg = "i" end -- Split into syllables local gen_pl = "" local syllable_count, syllables = split_into_syllables(stem) local word_syllable_count, word_syllables = split_into_syllables(word) -- Get the last and second-to-last syllables for rule checks local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" local word_penultimate_syllable = word_syllables[2] or "" -- 1. Add a vowel between the last two consonants of a cluster at the end of the stem if ends_with_consonant_cluster(last_syllable) then if matches_any(word, {"jedlo", "predjedlo", "jutro", "vrecko", "brvno"}) then if matches_any(word, {"jedlo", "predjedlo", "jutro"}) then gen_pl = remove_suffix(stem, stem_ultimate) .. "á" .. stem_ultimate else gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, stem_ultimate) .. "á" .. stem_ultimate}) end elseif sonorants_set[stem_ultimate] or ends_with_any(last_syllable, {"stv", "ctv", "íčk", "ečk", "očk"}) or TYPE == "dim" then if stem_penultimate ~= "j" and (word_syllable_count == 1 or ends_with_any(last_syllable, {"stv", "ctv"}) or is_short(word_penultimate_syllable)) then gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate elseif obstruents_set[stem_ultimate] and (is_long(word_penultimate_syllable) or stem_penultimate == "j") then gen_pl = remove_suffix(stem, stem_ultimate) .. "o" .. stem_ultimate elseif sonorants_set[stem_ultimate] and (is_long(word_penultimate_syllable) or stem_penultimate == "j") then gen_pl = remove_suffix(stem, stem_ultimate) .. "e" .. stem_ultimate if stem_penultimate ~= "j" then set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate}) end end end end -- 2. Add "í" if stem ends with a vowel or a soft consonant if gen_pl == "" and (vowels_set[stem_ultimate] or soft_consonants_set[stem_ultimate]) then gen_pl = stem .. "í" end -- 3. Return the stem with no change if conditions match if gen_pl == "" and (is_long(penultimate_syllable) or ends_with_any(stem, {"vojsk", "ov"}) or (TYPE == "loan" and matches_any(get_vowel(last_syllable), {"e", "o"}))) then gen_pl = stem end -- 4. Logic to use the lengthened vowel if conditions match if gen_pl == "" and (not (ends_with_consonant_cluster(last_syllable) or vowels_set[stem_ultimate]) or (ends_with_consonant_cluster(last_syllable) and obstruents_set[stem_ultimate])) then gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable) end local nom_pl = "á" if NUMBER == "pl" then nom_pl = ultimate end if gen_pl == "" then gen_pl = stem end if (is_long(word_penultimate_syllable) or word == "jojo") and not ends_with(word, "ium") then append_endings(forms, word, stem, "a", "u", nil, loc_sg, "om", "a", gen_pl, "am", nil, "ach", "ami" ) else append_endings(forms, word, stem, "a", "u", nil, loc_sg, "om", nom_pl, gen_pl, "ám", nil, "ách", "ami" ) end if matches_any(word, {"oko", "ucho"}) then local pl_stem = (word == "oko") and "oč" or "uš" append_second_plural(forms, pl_stem .. "i", pl_stem .. "í", pl_stem .. "iam", nil, pl_stem .. "iach", pl_stem .. "ami") switch_plural_forms(forms) --changes the prefered forms set_forms(forms, {"gen_pl2"}, {pl_stem .. "ú"} ) elseif word == "nebo" then set_forms(forms, {"nom_pl", "nom_pl2", "gen_pl", "dat_pl", "dat_pl2", "acc_pl", "acc_pl2", "loc_pl", "loc_pl2", "ins_pl"}, {"nebesá", "nebesia", "nebies", "nebesám", "nebesiam", "nebesá", "nebesia", "nebesách", "nebesiach", "nebesami"} ) end return forms, title end declensions["srdce"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "e") if ends_with(word, "ě") then stem = remove_suffix(word, "ě") end local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("srdce") .. ")" if NUMBER == "pl" then if ends_with(word, "ia") then stem = remove_suffix(word, "ia") else stem = remove_suffix(word, "a") end end if ends_with(stem, "[dtnl]") then stem = soften_last_consonant(stem) end -- Split into syllables local gen_pl = "" local syllable_count, syllables = split_into_syllables(stem) local word_syllable_count, word_syllables = split_into_syllables(word) -- Get the last and second-to-last syllables for rule checks local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" local word_penultimate_syllable = word_syllables[2] or "" local last_char = get_last_char(stem) local stem_ultimate, stem_penultimate = get_last_letters(stem) -- 1 & 2. Lengthen the last syllable's vowel if conditions apply, -- otherwise leave the stem unchanged if penultimate syllable is long if not ends_with_consonant_cluster(last_syllable) or (ends_with(word, "ce") and matches_any(get_vowel(word_penultimate_syllable), {"r", "l"}) and TYPE ~= "dim") or ends_with(word, "ište") then if is_long(penultimate_syllable) then gen_pl = stem -- If penultimate syllable of the stem is long, use the stem unchanged else -- Otherwise, lengthen the last syllable's vowel gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable) end end -- 3. Add a vowel between the last two consonants if the conditions apply if gen_pl == "" and (word == "citoslovce" or word == "vajce" or ends_with(word, "ce")) then if stem_penultimate ~= "j" and is_short(word_penultimate_syllable) then gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate elseif is_long(word_penultimate_syllable) or stem_penultimate == "j" then gen_pl = remove_suffix(stem, stem_ultimate) .. "e" .. stem_ultimate end end -- 4. Add "í" to the stem for specific words if matches_any(word, {"more", "oje", "pole", "lože"}) then gen_pl = harden_last_consonant(stem) .. "í" end -- Fallback: if none of the rules apply, return the original stem if gen_pl == "" then gen_pl = stem end if is_long(word_penultimate_syllable) or ends_with(stem, "j") then append_endings(forms, word, stem, "a", "u", nil, "i", "om", "a", gen_pl, "am", nil, "ach", "ami" ) else append_endings(forms, word, stem, "a", "u", nil, "i", "om", "ia", gen_pl, "iam", nil, "iach", "ami" ) end return forms, title end declensions["vysvedčenie"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "ie") if ends_with(word, "í") then stem = remove_suffix(word, "í") end local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("vysvedčenie") .. ")" append_endings(forms, word, stem, "ia", "iu", nil, "í", "ím", "ia", stem .. "í", "iam", nil, "iach", "iami" ) if word == "storočie" then append_second_plural(forms, "stáročia", "stáročí", "stáročiam", nil, "stáročiach", "stáročiami") end return forms, title end declensions["dievča"] = function(word, genitive) local forms = {} local stem = remove_suffix(word, "a") if ends_with(word, "ä") then stem = remove_suffix(word, "ä") end local ending = get_last_char(word) local title = "Declension of ''" .. word .. "'' <br>(pattern " .. pattern_link("dievča") .. ")" local gen_pl = "" local syllable_count, syllables = split_into_syllables(word) local last_syllable = syllables[1] local penultimate_syllable = syllables[2] or "" if is_long(penultimate_syllable) then gen_pl = stem .. ending .. "t" else gen_pl = append_ending(stem, "iat") end append_endings(forms, word, stem, ending .. "ťa", ending .. "ťu", nil, ending .. "ti", ending .. "ťom", ending .. "tá", gen_pl, ending .. "tám", nil, ending .. "tách", ending .. "tami" ) local pl_stem = harden_last_consonant(stem) append_second_plural(forms, pl_stem .. "ence", pl_stem .. "eniec", pl_stem .. "encom", nil, pl_stem .. "encoch", pl_stem .. "encami") if matches_any(word, {"kura", "strídža", "drumblence", "gajdence", "deťúrence"}) then switch_plural_forms(forms) --changes the prefered forms unset_alt_forms(forms) elseif matches_any(word, {"páža", "knieža", "kurča", "plánča", "pôrča", "zviera", "pachoľa", "mláďa", "dúpä", "chlápä", "žieňa", "nemluvňa"}) then unset_alt_forms(forms) elseif matches_any(word, {"prasa", "teľa", "šteňa"}) then local pl_stem = (word == "šteňa") and "šten" or stem append_second_plural(forms, pl_stem .. "ce", append_ending(pl_stem, "iec"), pl_stem .. "com", nil, pl_stem .. "coch", pl_stem .. "cami") switch_plural_forms(forms) --changes the prefered forms elseif word == "dieťa" then set_forms(forms, {"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"}, {"deti", "detí", "deťom", "deti", "deťoch", "deťmi"} ) unset_alt_forms(forms) end return forms, title end declensions["adjective"] = function(word, genitive) local forms = {} local title = "Declension of ''" .. word .. "'' (adjective declension)" local ultimate, penultimate = get_last_letters(word) local lemma_form = word if NUMBER == "pl" then if ends_with(word, "é") then lemma_form = remove_suffix(word, "é") .. "ý" elseif ends_with(word, "ie") then lemma_form = remove_suffix(word, "ie") .. "í" elseif ends_with_any(word, {"ove", "ine"}) then lemma_form = remove_suffix(word, "e") elseif ends_with(word, "e") then lemma_form = remove_suffix(word, "e") .. "y" elseif ends_with(word, "í") and not soft_consonants_set[penultimate] then lemma_form = remove_suffix(word, "í") .. "ý" elseif ends_with(word, "i") and not soft_consonants_set[penultimate] then lemma_form = remove_suffix(word, "i") .. "y" end else if GENDER == "f" or GENDER == "n" then if ends_with_any(word, {"á", "é"}) then lemma_form = remove_last_char(word) .. "ý" elseif ends_with_any(word, {"ia", "ie"}) then lemma_form = remove_suffix(remove_last_char(word), "i") .. "í" elseif ends_with_any(word, {"ova", "ovo", "ina", "ino"}) then lemma_form = remove_last_char(word) elseif ends_with_any(word, {"a", "e"}) then lemma_form = remove_last_char(word) .. "y" end end end local forms_raw = m_adj.do_generate_forms({pagename=lemma_form}, "adjective").forms set_forms(forms, {"nom_sg"}, {forms_raw["nom_" .. get_first_char(GENDER)][1].form} ) -- Singular if GENDER == "f" then set_forms(forms, {"gen_sg", "dat_sg", "loc_sg", "ins_sg"}, { forms_raw["gen_f"][1].form, forms_raw["dat_f"][1].form, forms_raw["loc_f"][1].form, forms_raw["ins_f"][1].form } ) else set_forms(forms, {"gen_sg", "dat_sg", "loc_sg", "ins_sg"}, { forms_raw["gen_mn"][1].form, forms_raw["dat_mn"][1].form, forms_raw["loc_mn"][1].form, forms_raw["ins_mn"][1].form } ) end -- special accusative singular if GENDER == "m-pr" or GENDER == "m-anml" then set_forms(forms, {"acc_sg"}, {forms_raw["acc_m_an"][1].form} ) elseif GENDER == "m-in" then set_forms(forms, {"acc_sg"}, {forms_raw["acc_m_in"][1].form} ) else set_forms(forms, {"acc_sg"}, {forms_raw["acc_" .. get_first_char(GENDER)][1].form} ) end -- Plural set_forms(forms, {"gen_pl", "dat_pl", "loc_pl", "ins_pl"}, { forms_raw["gen_p"][1].form, forms_raw["dat_p"][1].form, forms_raw["loc_p"][1].form, forms_raw["ins_p"][1].form } ) if GENDER == "m-pr" then set_forms(forms, {"nom_pl", "acc_sg", "acc_pl"}, {forms_raw["nom_mp_an"][1].form, forms_raw["acc_m_an"][1].form, forms_raw["acc_mp_an"][1].form} ) else set_forms(forms, {"nom_pl", "acc_pl"}, {forms_raw["nom_fnp"][1].form, forms_raw["acc_fnp"][1].form} ) end return forms, title end declensions["indeclinable"] = function(word, genitive) local forms = {} local title = "Declension of ''" .. word .. "'' (indeclinable)" local cases = {"nom", "gen", "dat", "acc", "loc", "ins"} -- List of cases local numbers = {"sg", "pl"} for _, case in ipairs(cases) do for _, number in ipairs(numbers) do local form_key = case .. "_" .. number forms[form_key] = word end end -- Surnames ending with -ů, -eje, -oje and -ovie if TYPE == "surn" and ends_with_any(word, {"ů", "eje", "e", "oje", "ovie"}) then append_second_plural(forms, word .. "ovci", word .. "ovcov", word .. "ovcom", word .. "ovcov", word .. "ovcoch", word .. "ovcami") end return forms, title end --[=[ Partial declination functions ]=]-- function check_gender(gender) if gender == nil then return error("No gender entered. Please pass one of these values as parameter 1: m-pr, m-anml, m-in, f, n.") elseif allowed_genders_set[gender] then return gender else return error("Unknown gender. Please pass one of these values as parameter 1: m-pr, m-anml, m-in, f, n.") end end function determine_pattern(word, genitive) local pattern local phon_word = (PRONUNCIATION) and PRONUNCIATION or word local ultimate, penultimate = get_last_letters(phon_word) local first = get_first_char(phon_word) local dlan_endings = m_table.listToSet({"ň", "č", "ž", "ľ", "ď", "j", "š", "m", "z", "dz", "x"}) local dlan_exceptions_neg = m_table.listToSet({"reč", "seč", "lož", "beľ", "soľ", "mlaď", "meď", "myš", "voš"}) local dlan_exceptions_pos = m_table.listToSet({"obec", "pec", "čelusť", "kysť", "päsť", "Provence"}) local dlan_end_with_r_t = m_table.listToSet({"kader", "neter", "šír", "tvár", "činovať", "drobäť", "droboť", "hať", "hrochoť", "Hrochoť", "hrsť", "inovať", "labuť", "niť", "obeť", "paruť", "pažiť", "pečať", "perepúť", "perleť", "peruť", "pípeť", "plť", "postať", "prť", "púť", "sieť", "sihoť", "stať", "štvrť", "trať", "úvrať", "vňať", "violeť", "záhať", "žlť"}) local stroj_exceptions_pos = {"timbre", "cól", "gáfor", "hámor", "kôpor", "kufor", "Pôtor", "šiator", "pedál", "sandál", "kanál", "peniaz", "daniel"} local stroj_exceptions_neg = {"nesvár", "nešvár", "pár", "suchopár", "svár", "ker"} if matches_any(ultimate, {"r", "l"}) and penultimate == "e" and not ends_with(phon_word, "ier") and genitive == nil then genitive = phon_word .. "a" end if mw.ustring.find(phon_word, " ") or word == genitive then return "indeclinable" end if NUMBER == "pl" then if matches_any(ultimate, {"é", "i", "í"}) or (ultimate == "e" and ends_with(genitive, "ch")) then pattern = "adjective" elseif GENDER == "m-in" then if ultimate == "y" then pattern = "dub" else pattern = "stroj" end elseif GENDER == "f" then if ultimate == "y" then pattern = "žena" else pattern = "ulica" end elseif GENDER == "n" then if ultimate == "á" then pattern = "mesto" elseif penultimate == "i" and ultimate == "a" then pattern = "srdce" else if soft_consonants_set[penultimate] then pattern = "srdce" else pattern = "mesto" end end end else if GENDER == "m-pr" then if (matches_any(ultimate, {"y", "ý", "i", "í"}) and not ends_with_any(genitive, {"[yií]ho", "a"}) and not (TYPE == "surn" and matches_any(penultimate .. ultimate, {"ay", "ai"}))) or (matches_any(penultimate .. ultimate, {"ov", "in"}) and ends_with_any(genitive, {"ovho", "inho"})) then pattern = "adjective" elseif ultimate == "a" or (TYPE == "surn" and matches_any(ultimate, {"e", "ě"}) and (penultimate .. ultimate == "ně" or ends_with(genitive, "u"))) then pattern = "hrdina" elseif (matches_any(ultimate, {"i", "í", "y", "e", "é", "ä"}) or (TYPE == "name" and matches_any(ultimate, {"ü", "ö", "ő"})) or matches_any(phon_word, {"Hrabě", "Poupě"})) and not (TYPE == "surn" and (ends_with_any(phon_word, {"ay", "ai", "eje", "oje", "ovie"}) or ends_with(genitive, "a"))) then pattern = "kuli" elseif TYPE == "surn" and ends_with_any(phon_word, {"ů", "eje", "oje", "ovie"}) then pattern = "indeclinable" else pattern = "chlap" end elseif GENDER == "m-in" or GENDER == "m-anml" then if matches_any(ultimate, {"y", "ý", "i", "í"}) or (matches_any(penultimate .. ultimate, {"ov", "in"}) and ends_with(genitive, "ho")) then pattern = "adjective" elseif (soft_consonants_set[ultimate] or (matches_any(ultimate, {"r", "l"}) and penultimate == "e" and (ends_with(genitive, "[^e][rl]a"))) or ends_with_any(phon_word, {"ár", "iar", "ier"}) or matches_any(phon_word, stroj_exceptions_pos)) and not matches_any(phon_word, stroj_exceptions_neg) then pattern = "stroj" else pattern = "dub" end elseif GENDER == "f" then if matches_any(phon_word, {"gazdiná", "švagriná", "testiná", "ujčiná", "stryná", "kňažná", "kráľovná", "cisárovná", "cárovná", "šľachtičná", "princezná" }) then pattern = "gazdiná" elseif ultimate == "a" and not ends_with(genitive, "ej") then if soft_consonants_set[penultimate] or matches_any(penultimate, {"i", "y"}) or matches_any(phon_word, {"rozopra", "konopa", "večera"}) then pattern = "ulica" else pattern = "žena" end elseif matches_any(ultimate, {"a", "á"}) or (ends_with_any(phon_word, {"ova", "ina"}) and ends_with(genitive, "ej")) then pattern = "adjective" elseif ends_with(phon_word, "pani") or matches_any(phon_word, {"Mať", "mať", "mater", "mati"}) then pattern = "irregular" else if not dlan_exceptions_neg[phon_word] and (dlan_endings[ultimate] or dlan_exceptions_pos[phon_word] or dlan_end_with_r_t[phon_word] or (penultimate == "š" and ultimate == "ť" and not is_capital(first))) then pattern = "dlaň" else pattern = "kosť" end end if genitive then local g_ultimate = get_last_char(genitive) if g_ultimate == "y" then pattern = "žena" elseif g_ultimate == "i" then pattern = "kosť" end end elseif GENDER == "n" then if (ultimate == "o" or (penultimate == "u" and ultimate == "m") or (penultimate == "o" and ultimate == "n") or (penultimate == "m" and ultimate == "ä")) and not ends_with(genitive, "ho") then pattern = "mesto" elseif (penultimate == "i" and ultimate == "e") or ultimate == "í" then pattern = "vysvedčenie" elseif (ultimate == "e" or ultimate == "ě") and not ends_with(genitive, "ho") then pattern = "srdce" elseif matches_any(ultimate, {"a", "ä"}) then pattern = "dievča" elseif matches_any(ultimate, {"e", "é"}) or ends_with_any(phon_word, {"ovo", "ino"}) then pattern = "adjective" else pattern = "indeclinable" end end end return pattern end function append_ending(stem1, ending) if matches_any(get_first_char(ending), {"e", "i", "é", "í"}) then return harden_last_consonant(stem1) .. ending else return stem1 .. ending end end function append_endings(forms, word, stem, end2, end3, end4, end5, end6, end7, gen_pl, end9, end10, end11, end12) forms["nom_sg"] = word forms["gen_sg"] = append_ending(stem, end2) forms["dat_sg"] = append_ending(stem, end3) if GENDER == "m-pr" or (GENDER == "f" and (ends_with_any(word, {"pani", "a", "á"}) or matches_any(word, {"Mať", "mať", "mater", "mati"}))) then forms["acc_sg"] = append_ending(stem, end4) else forms["acc_sg"] = word end forms["loc_sg"] = append_ending(stem, end5) forms["ins_sg"] = append_ending(stem, end6) local nom_pl = stem if ends_with_any(stem, {"k", "ch"}) and matches_any(GENDER, {"m-pr", "m-anml"}) and end7 == "i" then if ends_with(stem, "k") then nom_pl = remove_suffix(stem, "k") .. "c" else nom_pl = remove_suffix(stem, "ch") .. "s" end end forms["nom_pl"] = append_ending(nom_pl, end7) forms["gen_pl"] = gen_pl forms["dat_pl"] = append_ending(stem, end9) if GENDER == "m-pr" or end10 or (GENDER == "f" and (ends_with_any(word, {"pani"}) or matches_any(word, {"Mať", "mať", "mater", "mati"}))) then forms["acc_pl"] = append_ending(stem, end10) else forms["acc_pl"] = forms["nom_pl"] end forms["loc_pl"] = append_ending(stem, end11) forms["ins_pl"] = append_ending(stem, end12) end function set_forms(forms, indices, values) for i = 1, #indices do forms[indices[i]] = values[i] end end function switch_plural_forms(forms) local indices = {"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"} for _, index in ipairs(indices) do forms[index], forms[index .. "_alt"] = forms[index .. "_alt"], forms[index] end end function unset_alt_forms(forms) for key in pairs(forms) do if mw.ustring.find(key, "_alt$") then forms[key] = nil end end end function append_alternative_singular(forms, form2, form3, form4, form5, form6) forms["gen_sg2"] = (forms["gen_sg"] ~= form2) and form2 forms["dat_sg2"] = (forms["dat_sg"] ~= form3) and form3 if matches_any(GENDER, {"m-pr", "m-anml"}) or (GENDER == "f" and (ends_with_any(word, {"pani", "a", "á"}) or matches_any(word, {"Mať", "mať", "mater", "mati"}))) then forms["acc_sg2"] = (forms["acc_sg"] ~= form4) and form4 end forms["loc_sg2"] = (forms["loc_sg"] ~= form5) and form5 forms["ins_sg2"] = (forms["ins_sg"] ~= form6) and form6 end function append_alternative_plural(forms, form1, form2, form3, form4, form5, form6) forms["nom_pl2"] = (forms["nom_pl"] ~= form2) and form1 forms["gen_pl2"] = (forms["gen_pl"] ~= form2) and form2 forms["dat_pl2"] = (forms["dat_pl"] ~= form2) and form3 if form4 ~= nil and forms["acc_pl"] ~= form4 then forms["acc_pl2"] = form4 elseif forms["acc_pl"] ~= form1 then forms["acc_pl2"] = form1 end forms["loc_pl2"] = (forms["loc_pl"] ~= form2) and form5 forms["ins_pl2"] = (forms["ins_pl"] ~= form2) and form6 end function append_second_plural(forms, form1, form2, form3, form4, form5, form6) forms["nom_pl_alt"] = form1 forms["gen_pl_alt"] = form2 forms["dat_pl_alt"] = form3 if form4 ~= nil then forms["acc_pl_alt"] = form4 else forms["acc_pl_alt"] = forms["nom_pl_alt"] end forms["loc_pl_alt"] = form5 forms["ins_pl_alt"] = form6 end function append_animal_singular(forms, stem) set_forms(forms, {"gen_sg", "dat_sg", "acc_sg", "loc_sg"}, { append_ending(stem, "a"), append_ending(stem, "ovi"), append_ending(stem, "a"), append_ending(stem, "ovi") } ) end function get_last_char(str) local last = mw.ustring.sub(str, -1, -1) return last end function get_first_char(str) local first = mw.ustring.sub(str, 1, 1) return first end function remove_last_char(str) local stem = mw.ustring.sub(str, 1, -2) return stem end function is_capital(str) return mw.ustring.find(str, "[A-Z]") end function get_last_letters(word) local ultimate = get_last_char(word) local penultimate = get_last_char(remove_last_char(word)) local antepenultimate = get_last_char(remove_last_char(remove_last_char(word))) if (penultimate == "c" and ultimate == "h") or (penultimate == "d" and (ultimate == "z" or ultimate == "ž")) then ultimate = penultimate .. ultimate penultimate = antepenultimate antepenultimate = get_last_char(remove_last_char(remove_last_char(remove_last_char(word)))) end if (antepenultimate == "c" and penultimate == "h") or (antepenultimate == "d" and (penultimate == "z" or penultimate == "ž")) then penultimate = antepenultimate .. penultimate end if penultimate == "v" and consonants_set[ultimate] and not matches_any(ultimate, {"r", "l", "ŕ", "ĺ"}) then penultimate = "ʋ" end return ultimate, penultimate end function ends_with(word, suffix) -- Check if suffix matches the end of word word = (word ~= nil) and word or "" return mw.ustring.find(word, suffix .. "$") ~= nil end function ends_with_any(word, suffixes) for _, suffix in ipairs(suffixes) do if ends_with(word, suffix) then return true -- Return true if any suffix matches end end return false -- Return false if no suffix matches end function matches_any(value, list) for _, item in ipairs(list) do if value == item then return true end end return false end function get_vowel(syllable) -- Define patterns for diphthongs and vowels local diphthong_pattern = "ia|ie|iu|ô" local vowel_pattern = "[aeiouyáéíóúýäöőüű]" local syllabic_consonant_pattern = "[rl]" -- Check for a diphthong first local diphthong = mw.ustring.match(syllable, diphthong_pattern) if diphthong then return diphthong end -- Check for a single vowel local vowel = mw.ustring.match(syllable, vowel_pattern) if vowel then return vowel end -- Check for a syllabic consonant if no vowel is found local syllabic_consonant = mw.ustring.match(syllable, syllabic_consonant_pattern) if syllabic_consonant then return syllabic_consonant end return nil -- Return nil if no vowel or syllabic consonant is found end -- Function to split a word into characters and bigraphs function split_into_letter_units(word) local units = {} local i_word = 1 local i_pron = 1 local word_len = mw.ustring.len(word) local pron_len = PRONUNCIATION and mw.ustring.len(PRONUNCIATION) or 0 while i_word <= word_len do local two_char = mw.ustring.sub(word, i_word, i_word + 1) -- Check if PRONUNCIATION forbids combining here local combine_forbidden = false if PRONUNCIATION then -- Advance pronunciation pointer to skip slashes until it aligns with actual letters -- We only block combination if the *next* character in PRON is a slash while i_pron <= pron_len and mw.ustring.sub(PRONUNCIATION, i_pron, i_pron) == "/" do i_pron = i_pron + 1 end -- Look ahead: is the *next* pronunciation char a slash? if i_pron < pron_len then local next_ch = mw.ustring.sub(PRONUNCIATION, i_pron + 1, i_pron + 1) if next_ch == "/" then combine_forbidden = true end end end -- Normal combination if allowed if not combine_forbidden and (bigraphs_set[two_char] or diphthongs_set[two_char]) then table.insert(units, two_char) i_word = i_word + 2 i_pron = i_pron + 2 -- move pronunciation index along with it else -- Fallback: single character local char = mw.ustring.sub(word, i_word, i_word) table.insert(units, char) i_word = i_word + 1 i_pron = i_pron + 1 end end return units end -- check if a unit is a vowel or syllabic element function is_vowel(unit, prev_unit, next_unit) if diphthongs_set[unit] then return true end if vowels_set[unit] then return true end -- Check if 'r' or 'l' are syllabic (preceded and followed by consonants) if matches_any(unit, {"r", "ŕ", "l", "ĺ"}) and prev_unit and next_unit and not (vowels_set[prev_unit] or vowels_set[next_unit] or diphthongs_set[prev_unit] or diphthongs_set[next_unit]) then return true end return false end -- Function to split a word into syllables according to Slovak rules function split_into_syllables(word) local units = split_into_letter_units(word) local syllables = {} local current_syllable = "" local i = 1 local length = #units local first_vowel_found = false -- Flag to indicate when the first vowel has been encountered -- Iterate over the units in the word while i <= length do local unit = units[i] local next_unit = i < length and units[i + 1] or nil local previous_unit = i > 1 and units[i - 1] or nil local is_current_vowel = is_vowel(unit, previous_unit, next_unit) -- If we haven't encountered the first vowel, keep adding to the first syllable if not first_vowel_found then current_syllable = current_syllable .. unit if is_current_vowel then first_vowel_found = true -- Mark that the first vowel has been found end else if is_current_vowel then -- If a vowel is encountered after the first vowel has been found, finalize the current syllable if current_syllable ~= "" and is_vowel(previous_unit, nil, nil) then table.insert(syllables, current_syllable) current_syllable = "" end current_syllable = current_syllable .. unit else -- Handling consonants between vowels local consonant_cluster = unit -- Collect any consecutive consonants into a cluster local j = i + 1 while j <= length and not is_vowel(units[j], units[j - 1], units[j + 1]) do consonant_cluster = consonant_cluster .. units[j] j = j + 1 end local consonant_count = mw.ustring.len(consonant_cluster) if next_unit and is_vowel(next_unit, unit, units[j]) then -- Apply syllable rules based on the number of consonants in the cluster if consonant_count == 1 then -- Rule 3: Single consonant goes to the next syllable table.insert(syllables, current_syllable) -- End the current syllable without the consonant current_syllable = consonant_cluster -- Start the next syllable with the consonant elseif consonant_count == 2 then -- Rule 4: Two consonants split between syllables current_syllable = current_syllable .. mw.ustring.sub(consonant_cluster, 1, 1) table.insert(syllables, current_syllable) current_syllable = mw.ustring.sub(consonant_cluster, 2, 2) else -- Rule 5: Three or more consonants - first goes with current syllable, rest with next current_syllable = current_syllable .. mw.ustring.sub(consonant_cluster, 1, 1) table.insert(syllables, current_syllable) current_syllable = mw.ustring.sub(consonant_cluster, 2) end i = j - 1 -- Adjust the index to skip the processed consonants else current_syllable = current_syllable .. unit end end end i = i + 1 end -- Add any remaining characters as the final syllable if #current_syllable > 0 then table.insert(syllables, current_syllable) end -- Reverse the syllables array for the requested output order local reversed_syllables = {} for j = #syllables, 1, -1 do reversed_syllables[#reversed_syllables + 1] = syllables[j] end -- Return the count of syllables and the reversed syllable array return #syllables, reversed_syllables end function is_long(syllable) return mw.ustring.find(syllable, "[áéíóúýôĺŕ]") ~= nil or mw.ustring.find(syllable, "i[aeu]") ~= nil end function is_short(syllable) return not is_long(syllable) end local function get_last_consonant_before_vowel(syllable) local vowel = get_vowel(syllable) -- If there is no vowel in the syllable, return false if not vowel then return false end -- Find the position of the vowel in the syllable local vowel_pos = mw.ustring.find(syllable, vowel) -- Loop backwards from the position of the vowel to find the last consonant for i = vowel_pos - 1, 1, -1 do local char = mw.ustring.sub(syllable, i, i) if not mw.ustring.find(char, "[aeiouáéíóúýôä]") then return char -- Return the last consonant before the vowel end end return false -- Return false if no consonant is found before the vowel end -- Function to lengthen the last vowel in a syllable if it’s not already long function lengthen_vowel(syllable) if is_long(syllable) then return syllable -- Return as-is if the syllable is already long end local lengthening_map = { ["a"] = "á", ["i"] = "í", ["y"] = "ý", ["u"] = "ú", ["ä"] = "ia", ["e"] = "ie", ["o"] = "ô" } local cons_map = { ["ď"] = "d", ["ť"] = "t", ["ň"] = "n", ["ľ"] = "l" } -- Check for regular vowels first and replace if found for vowel, long_vowel in pairs(lengthening_map) do if mw.ustring.find(syllable, vowel) then -- if there is a soft consonant before "a", it becomes "ia" instead of "á" local last_cons = get_last_consonant_before_vowel(syllable) or "" if soft_consonants_set[last_cons] and last_cons ~= "j" and vowel == "a" then long_vowel = "ia" end -- if a or ä changes into "ia", the previous consonant should be written as hard if matches_any(vowel, {"ä", "a"}) and matches_any(last_cons, {"ď", "ť", "ň", "ľ"}) then syllable = mw.ustring.gsub(syllable, last_cons .. vowel, cons_map[last_cons] .. vowel, 1) end syllable = mw.ustring.gsub(syllable, vowel, long_vowel, 1) return syllable -- Return immediately after replacing a regular vowel end end -- Only replace "r" and "l" if no other vowels were found if not mw.ustring.find(syllable, "[aeiouyáéíóúýôä]") then syllable = mw.ustring.gsub(syllable, "r", "ŕ") syllable = mw.ustring.gsub(syllable, "l", "ĺ") end return syllable end -- Helper function to determine if the syllable ends with a consonant cluster function ends_with_consonant_cluster(last_syllable) local last_char = get_last_char(last_syllable) local second_last_char = mw.ustring.sub(last_syllable, -2, -2) local third_last_char = mw.ustring.sub(last_syllable, -3, -3) local last_two_chars = mw.ustring.sub(last_syllable, -2) -- Check if the syllable contains any regular vowels local has_vowel = mw.ustring.find(last_syllable, "[aeiouyáéíóúýôä]") if has_vowel then -- If the last two characters form a digraph, check the third-last character for a cluster if bigraphs_set[last_two_chars] then return not vowels_set[third_last_char] else -- If no digraph, just check the last two characters return not (vowels_set[last_char] or vowels_set[second_last_char] or diphthongs_set[last_char] or diphthongs_set[second_last_char]) end else -- No regular vowel; treat `r` or `l` as syllabic if either is in the last two characters if matches_any(last_char, {'ŕ', 'ĺ'}) or matches_any(second_last_char, {'ŕ', 'ĺ'}) then return false elseif mw.ustring.find(last_syllable, "[bcčdďfghjkľmnňpqsštťvwxzž][rl][bcčdďfghjkľmnňpqysštťvwxzž][rl]$") then return true else -- No syllabic `r` or `l`, so both characters are treated as consonants return not vowels_set[last_char] and not vowels_set[second_last_char] end end end function remove_mobile_vowel(word) local units = split_into_letter_units(word) -- Split word into units for i = #units, 1, -1 do local unit = units[i] if matches_any(unit, {"e", "ie", "o", "i", "á"}) then -- Remove the mobile vowel unit and reassemble the word table.remove(units, i) return table.concat(units) end end return word -- Return the original word if no mobile vowel is found end function soften_last_consonant(str) local consonants_t = { ["c"] = "č", ["d"] = "ď", ["l"] = "ľ", ["n"] = "ň", ["s"] = "š", ["t"] = "ť", ["z"] = "ž" } local last_char = get_last_char(str) -- Check if the last character is in consonants_t and replace if needed return consonants_t[last_char] and remove_last_char(str) .. consonants_t[last_char] or str end function harden_last_consonant(str) local soft_to_hard = { ["ď"] = "d", ["ť"] = "t", ["ň"] = "n", ["ľ"] = "l" } local last_char = get_last_char(str) -- Check if the last character is a soft consonant and replace if needed return soft_to_hard[last_char] and remove_last_char(str) .. soft_to_hard[last_char] or str end function remove_suffix(form, suffix) if mw.ustring.find(form, suffix .. "$") then local length = mw.ustring.len(suffix) return mw.ustring.sub(form, 1, -length-1) end return form end function pattern_link(pattern) return "''[[Appendix:Slovak declension pattern " .. pattern .. "|" .. pattern .. "]]''" end function decline_with_more_stems(genitive) local genitives = {} for part in mw.ustring.gmatch(genitive, "[^/]+") do table.insert(genitives, part) end local forms, title = declensions[PATTERN](PAGENAME, genitives[1]) normalize_forms(forms) local forms2, title2 = declensions[PATTERN](PAGENAME, genitives[2]) normalize_forms(forms2) append_alternative_singular(forms, forms2["gen_sg"], forms2["dat_sg"], forms2["acc_sg"], forms2["loc_sg"], forms2["ins_sg"]) append_alternative_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"], forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"]) return forms, title end function split_into_units(expression, genitive) -- Split the original expression into words local words = {} for word in mw.ustring.gmatch(expression, "%S+") do table.insert(words, word) end -- Split the genitive phrase into words, if provided local gen_words = {} if genitive then for word in mw.ustring.gmatch(genitive, "%S+") do table.insert(gen_words, word) end -- Check if the genitive phrase has the same structure as the original if #gen_words ~= #words then error("Genitive phrase must have the same number of words as the original expression.") end end -- Combine words into units, grouping prepositional phrases for both expressions local units = {} local gen_units = {} local i = 1 while i <= #words do if prepositions_set[words[i]] and words[i + 1] then -- Combine preposition with the following words as one unit local phrase = words[i] local gen_phrase = genitive and gen_words[i] or nil i = i + 1 while i <= #words do phrase = phrase .. " " .. words[i] if genitive then gen_phrase = gen_phrase .. " " .. gen_words[i] end if i == #words then table.insert(units, phrase) if genitive then table.insert(gen_units, gen_phrase) end end i = i + 1 end else -- Add standalone word as a unit table.insert(units, words[i]) if genitive then table.insert(gen_units, gen_words[i]) end i = i + 1 end end -- Return both units and genitive units return units, gen_units end function generate_combined_forms(units, gen_units) -- Process each unit to generate forms local all_forms = {} local patterns = "" for i = 1, #units do local unit = units[i] local gen_unit = gen_units[i] if conjunctions_set[unit] or unit == gen_unit then -- Conjunctions are indeclinable local forms = declensions["indeclinable"](unit, gen_unit) table.insert(all_forms, forms) else -- Decline each unit using determine_pattern and declensions local pattern = determine_pattern(unit, gen_unit) local forms, title = declensions[pattern](unit, gen_unit) normalize_forms(forms) table.insert(all_forms, forms) end end -- Combine forms into a single forms table local combined_forms = {} local cases = {"nom", "gen", "dat", "acc", "loc", "ins"} local numbers = {"sg", "pl"} -- check if vocative and plural 2 forms are necessary for _, forms in ipairs(all_forms) do if forms["voc_sg"] and #cases == 6 then table.insert(cases, "voc") end if forms["nom_pl_alt"] and #numbers == 2 then table.insert(numbers, "pl_alt") end end for _, case in ipairs(cases) do for _, number in ipairs(numbers) do local form_key = case .. "_" .. number local combined_form, highest_index = {}, 1 -- Gather primary and numbered alternative forms (e.g., gen_sg2, gen_sg3) for _, forms in ipairs(all_forms) do local primary_form = forms[form_key] or forms["nom_" .. number] or forms[case .. "_pl"] table.insert(combined_form, primary_form) -- Check the highest alternative index for alt_index = 2, 4 do local alt_key = form_key .. alt_index if forms[alt_key] then highest_index = alt_index end end end -- Combine primary forms combined_forms[form_key] = mw.ustring.gsub(table.concat(combined_form, " "), "^%s+", "") -- Combine alternative forms if present if highest_index > 1 then for alt_index = 2, highest_index do -- Check and add numbered alternative forms local alt_key = form_key .. alt_index alt_form = {} for _, forms in ipairs(all_forms) do local primary_form = forms[form_key] or forms["nom_" .. number] if forms[alt_key] then table.insert(alt_form, forms[alt_key]) else table.insert(alt_form, primary_form) end end combined_forms[alt_key] = mw.ustring.gsub(table.concat(alt_form, " "), "^%s+", "") end end end end return combined_forms end function normalize_forms(forms) -- Step 1: Remove forms based on NUMBER if NUMBER == "sg" then for key in pairs(forms) do if mw.ustring.find(key, "_pl") then forms[key] = nil -- Remove plural forms if "n" is "sg" end end elseif NUMBER == "pl" then for key in pairs(forms) do if mw.ustring.find(key, "_sg") then forms[key] = nil -- Remove singular forms if "n" is "pl" end end end -- Step 2: Ensure all mandatory indices are set local cases = {"nom", "gen", "dat", "acc", "loc", "ins"} local numbers = {"sg", "pl"} for _, case in ipairs(cases) do for _, number in ipairs(numbers) do local form_key = case .. "_" .. number if not forms[form_key] then forms[form_key] = "&mdash;" -- Set missing forms to &mdash; end end end -- Step 3: Create missing _pl_alt indices if at least one exists local has_alt_plural = false for key in pairs(forms) do if mw.ustring.find(key, "_pl_alt") then has_alt_plural = true break end end if has_alt_plural then for _, case in ipairs(cases) do local form_key_alt = case .. "_pl_alt" if not forms[form_key_alt] then forms[form_key_alt] = "&mdash;" -- Create missing _pl_alt forms end end end -- Step 4: Create vocative plural forms if voc_sg exists if forms["voc_sg"] then forms["voc_pl"] = forms["nom_pl"] -- Set voc_pl to nom_pl if has_alt_plural then forms["voc_pl_alt"] = forms["nom_pl_alt"] -- Set voc_pl_alt to nom_pl_alt if it exists end end end function specified_by_user(forms, args) local cases = {nom = true, gen = true, dat = true, acc = true, voc = true, loc = true, ins = true} local numbers = {sg = true, pl = true} for key, value in pairs(args) do -- Match the pattern "<case>_<number><optional digit>" using mw.ustring.match local case, number, optional_digit = mw.ustring.match(key, "^(%a%a%a)_(%a%a)(%d?)$") -- Check if it matches the cases and numbers you want if case and cases[case] and number and numbers[number] then forms[key] = make_link(value, case .. "|" .. get_first_char(number)) end end end function make_link(link, accel_form) local new_link = link -- If link is not empty, valid, and not "&mdash;", create the full link if link ~= "" and link and link ~= "&mdash;" then new_link = m_links.full_link({lang = lang, term = link, accel = {form = accel_form}}) end return new_link end function make_table_header(title) return mw.getCurrentFrame():expandTemplate{ title = 'inflection-table-top', args = { title = title, palette = 'blue', tall = 'yes' } } end function make_simple_row(forms, case) local case_code = mw.ustring.sub(case, 1, 3) local row = "<tr><th>" .. case .. "</th>" -- Singular if NUMBER ~= "pl" then row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_sg"], case_code .. "|s") .. "</span>" -- Loop to check and display secondary singular forms in the same cell for i = 2, 4 do local form_key = case_code .. "_sg" .. i if not forms[form_key] then break -- Exit loop if form doesn't exist end row = row .. ",<br /><span lang=\"sk\">" .. make_link(forms[form_key], case_code .. "|s") .. "</span>" end row = row .. "</td>" end -- Plural if NUMBER ~= "sg" then -- Primary plural form row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_pl"], case_code .. "|p") .. "</span>" -- Loop to check and display secondary plural forms in the same cell for i = 2, 4 do local form_key = case_code .. "_pl" .. i if not forms[form_key] then break -- Exit loop if form doesn't exist end row = row .. ",<br /><span lang=\"sk\">" .. make_link(forms[form_key], case_code .. "|p") .. "</span>" end row = row .. "</td>" -- Check for alternative plural and add it in a separate cell if forms[case_code .. "_pl_alt"] then row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_pl_alt"], case_code .. "|p") .. "</span></td>" end end row = row .. "</tr>" return row end function make_table_header2(forms) local tr_open = "<tr><th></th>" local singular = "<th>singular</th>" local plural = "<th>plural</th>" local plural1 = "<th>plural 1</th>" local plural2 = "<th>plural 2</th>" local tr_close = "</tr>" local alt_plural = false if forms["nom_pl_alt"] or forms["gen_pl_alt"] or forms["dat_pl_alt"] or forms["acc_pl_alt"] or forms["loc_pl_alt"] or forms["ins_pl_alt"] then alt_plural = true end local header if NUMBER == "sg" then header = tr_open .. singular .. tr_close elseif NUMBER == "pl" then if alt_plural then header = tr_open .. plural1 .. plural2 .. tr_close else header = tr_open .. plural .. tr_close end elseif alt_plural then header = tr_open .. singular .. plural1 .. plural2 .. tr_close else header = tr_open .. singular .. plural .. tr_close end return header end function make_table_footer() return '\n' .. mw.getCurrentFrame():expandTemplate{ title = 'inflection-table-bottom' } end -- Make the table function make_table(forms, title) for key, form in pairs(forms) do -- check for empty strings and nil's if form == "" or not form then forms[key] = "&mdash;" end end local final = make_table_header(title) final = final .. make_table_header2(forms) final = final .. make_simple_row(forms, "မဒုၚ်ယၟု") final = final .. make_simple_row(forms, "ဗဳဇဂကူ") final = final .. make_simple_row(forms, "ပြကမ္မကာရက") final = final .. make_simple_row(forms, "ကမ္မကာရက") if forms["voc_sg"] then final = final .. make_simple_row(forms, "ပရေၚ်ဂယိုၚ်လမျီု") end final = final .. make_simple_row(forms, "ခၞံဗဒှ်ဌာန်မတန်တဴ") final = final .. make_simple_row(forms, "တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်") final = final .. make_table_footer() return final end return export im55qtquta13nkel5od2zbv7iprv5ey မဝ်ဂျူ:sk-noun/doc 828 295619 396271 2026-06-03T17:43:57Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|sk}} </includeonly>" 396271 wikitext text/x-wiki {{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|sk}} </includeonly> qgff6xi7s8bj8nl5sj8qwk3w0qp5tp5 ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲသလဝ်ဝေန်နဳယျာဂမၠိုၚ် 14 295620 396272 2026-06-03T17:47:54Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]]ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမ..." 396272 wikitext text/x-wiki [[ကဏ္ဍ:မဝ်ဂျူသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသလဝ်ဝေန်နဳယျာဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]] ko1rmg9grdb6wmfks6ti8gpnvqkjmvg မဝ်ဂျူ:sk-adjective 828 295621 396273 2026-06-04T03:59:18Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local export = {} --[=[ Authorship: Zhnka, heavily based on [[Module:cs-adjective]] by Benwing ]=] --[=[ TERMINOLOGY: -- "slot" = A particular combination of case/gender/number. Example slot names for adjectives are "gen_f" (genitive feminine singular) and "nom_mp_an" (animate nominative masculine plural). Each slot is filled with zero or more forms. -- "form" = The declined Slovak form representing the va..." 396273 Scribunto text/plain local export = {} --[=[ Authorship: Zhnka, heavily based on [[Module:cs-adjective]] by Benwing ]=] --[=[ TERMINOLOGY: -- "slot" = A particular combination of case/gender/number. Example slot names for adjectives are "gen_f" (genitive feminine singular) and "nom_mp_an" (animate nominative masculine plural). Each slot is filled with zero or more forms. -- "form" = The declined Slovak form representing the value of a given slot. -- "lemma" = The dictionary form of a given Slovak term. Generally the nominative masculine singular, but may occasionally be another form if the nominative masculine singular is missing. ]=] local lang = require("Module:languages").getByCode("sk") local m_links = require("Module:links") local m_table = require("Module:table") local m_string_utilities = require("Module:string utilities") local iut = require("Module:inflection utilities") local put = require("Module:parse utilities") local com = require("Module:sk-common") local en_utilities_module = "Module:en-utilities" local u = mw.ustring.char local rsplit = mw.text.split local rfind = mw.ustring.find local rmatch = mw.ustring.match local rgmatch = mw.ustring.gmatch local rsubn = mw.ustring.gsub local ulen = mw.ustring.len local uupper = mw.ustring.upper -- version of rsubn() that discards all but the first return value local function rsub(term, foo, bar) local retval = rsubn(term, foo, bar) return retval end -- version of rsubn() that returns a 2nd argument boolean indicating whether -- a substitution was made. local function rsubb(term, foo, bar) local retval, nsubs = rsubn(term, foo, bar) return retval, nsubs > 0 end -- All slots that are used by any of the different tables. The key is the slot and the value is a list of the tables -- that use the slot. "" = regular, "plonly" = special=plonly in {{sk-adecl-manual}}, "numeral" = special=numeral in -- {{sk-adecl-manual}}. local input_adjective_slots = { nom_m = {""}, nom_f = {""}, nom_n = {""}, nom_mp_an = {"", "plonly", "numeral"}, nom_mp_in = {"numeral"}, nom_fnp = {"", "plonly", "numeral"}, gen_mn = {""}, gen_f = {""}, gen_p = {"", "plonly", "numeral"}, dat_mn = {""}, dat_f = {""}, dat_p = {"", "plonly", "numeral"}, acc_m_an = {""}, acc_m_in = {""}, acc_f = {""}, acc_n = {""}, acc_mp_an = {"", "numeral"}, acc_fnp = {"", "numeral"}, ins_mn = {""}, ins_f = {""}, ins_p = {"", "plonly", "numeral"}, loc_mn = {""}, loc_f = {""}, loc_p = {"", "plonly", "numeral"}, short_m = {""}, short_f = {""}, short_n = {""}, short_mp_an = {""}, short_fnp = {""}, } local output_adjective_slots = { nom_m = "nom|m|s", nom_m_linked = "nom|m|s", -- used in [[Module:sk-noun]]? nom_f = "nom|f|s", nom_n = "nom|n|s", nom_mp_an = "an|nom|m|p", nom_mp_in = "in|nom|m|p", nom_mp = "nom|m|p", nom_fnp = "in|nom|m|p|;|nom|f//n|p", gen_mn = "gen|m//n|s", gen_f = "gen|f|s", gen_p = "gen|p", dat_mn = "dat|m//n|s", dat_f = "dat|f|s", dat_p = "dat|p", acc_m_an = "an|acc|m|s", acc_m_in = "in|acc|m|s", acc_f = "acc|f|s", acc_n = "acc|n|s", acc_mp_an = "an|acc|m|p", acc_mp_in = "in|acc|m|p", acc_fnp = "in|acc|m|p|;|acc|f//n|p", ins_mn = "ins|m//n|s", ins_f = "ins|f|s", ins_p = "ins|p", loc_mn = "loc|m//n|s", loc_f = "loc|f|s", loc_p = "loc|p", short_m = "short|m|s", short_f = "short|f|s", short_n = "short|n|s", short_mp_an = "short|an|m|p", short_fnp = "short|in|m|p|;|short|f//n|p", } local function get_output_adjective_slots(alternant_multiword_spec) return output_adjective_slots end local function combine_stem_ending(stem, ending) if stem == "?" then return "?" else return stem .. ending end end local function add(base, slot, stems, endings, footnote) if stems then stems = iut.combine_form_and_footnotes(stems, footnote) end iut.add_forms(base.forms, slot, stems, endings, combine_stem_ending) end local function add_normal_decl(base, stems, nom_m, nom_f, nom_n, nom_mp_an, nom_fnp, gen_mn, gen_f, gen_p, dat_mn, dat_f, dat_p, acc_f, loc_mn, loc_f, loc_p, ins_mn, ins_f, ins_p, footnote) if stems then stems = iut.combine_form_and_footnotes(stems, footnote) end add(base, "nom_m", stems, nom_m) add(base, "nom_f", stems, nom_f) add(base, "nom_n", stems, nom_n) add(base, "nom_mp_an", stems, nom_mp_an) add(base, "nom_fnp", stems, nom_fnp) add(base, "gen_mn", stems, gen_mn) add(base, "gen_f", stems, gen_f) add(base, "gen_p", stems, gen_p) add(base, "dat_mn", stems, dat_mn) add(base, "dat_f", stems, dat_f) add(base, "dat_p", stems, dat_p) add(base, "acc_f", stems, acc_f) add(base, "loc_mn", stems, loc_mn) add(base, "loc_f", stems, loc_f) add(base, "loc_p", stems, loc_p) add(base, "ins_mn", stems, ins_mn) add(base, "ins_f", stems, ins_f) add(base, "ins_p", stems, ins_p) end local function add_short_decl(base, stems, m, f, n, mp_an, fnp, footnote) if stems then stems = iut.combine_form_and_footnotes(stems, footnote) end add(base, "short_m", stems, m) add(base, "short_f", stems, f) add(base, "short_n", stems, n) add(base, "short_mp_an", stems, mp_an) add(base, "short_fnp", stems, fnp) end local decls = {} decls["normal"] = function(base) local stem, suffix -- hard-long in -ý stem, suffix = rmatch(base.lemma, "^(.*)(ý)$") if stem then add_normal_decl(base, stem, "ý", "á", "é", "í", "é", "ého", "ej", "ých", "ému", "ej", "ým", "ú", "om", "ej", "ých", "ým", "ou", "ými" ) if base.short then for _, short_stem_obj in ipairs(base.short) do add_short_decl(base, short_stem_obj.base, "") add_short_decl(base, short_stem_obj.stem, nil, "a", "o", "i", "y") end end return end -- hard-short in -y stem, suffix = rmatch(base.lemma, "^(.*)(y)$") if stem then add_normal_decl(base, stem, "y", "a", "e", "i", "e", "eho", "ej", "ych", "emu", "ej", "ym", "u", "om", "ej", "ych", "ym", "ou", "ymi" ) return end -- soft-long in -í stem, suffix = rmatch(base.lemma, "^(.*)(í)$") if stem then add_normal_decl(base, stem, "í", "ia", "ie", "í", "ie", "ieho", "ej", "ích", "iemu", "ej", "ím", "iu", {}, "ej", "ích", "ím", {}, "ími" ) add_normal_decl(base, com.convert_paired_plain_to_palatal(stem, ending), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, "om", nil, nil, nil, "ou") return end -- soft-short in -i stem, suffix = rmatch(base.lemma, "^(.*)(i)$") if stem then add_normal_decl(base, stem, "i", {}, "e", "i", "e", "eho", "ej", "ich", "emu", "ej", "im", {}, {}, "ej", "ich", "im", {}, "imi" ) add_normal_decl(base, com.convert_paired_plain_to_palatal(stem, ending), nil, "a", nil, nil, nil, nil, nil, nil, nil, nil, nil, "u", "om", nil, nil, nil, "ou") return end -- possessive in -ov stem, suffix = rmatch(base.lemma, "^(.*)(ov)$") if stem then add_normal_decl(base, stem, "ov", "ova", "ovo", "ovi", "ove", "ovho", "ovej", "ových", "ovmu", "ovej", "ovým", "ovu", "ovom", "ovej", "ových", "ovým", "ovou", "ovými" ) return end -- possessive in -in stem, suffix = rmatch(base.lemma, "^(.*)(in)$") if stem then add_normal_decl(base, stem, "in", "ina", "ino", "ini", "ine", "inho", "inej", "iných", "inmu", "inej", "iným", "inu", "inom", "inej", "iných", "iným", "inou", "inými" ) return end error("Unrecognized adjective lemma, should end in '-ý', '-y', '-í', '-i', '-ov' or '-in': '" .. base.lemma .. "'") end decls["irreg"] = function(base) local stem, suffix if base.lemma == "môj" then add_normal_decl(base, "", "môj", "moja", "moje", "moji", "moje", "môjho", "mojej", "mojich", "môjmu", "mojej", "mojim", "moju", "mojom", "mojej", "mojich", "mojím", "mojou", "mojimi" ) return end -- determiner like tvoj stem, suffix = rmatch(base.lemma, "^(.*)(oj)$") if stem then add_normal_decl(base, stem, "oj", "oja", "oje", "oji", "oje", "ojho", "ojej", "ojich", "ojmu", "ojej", "ojim", "oju", "ojom", "ojej", "ojich", "ojím", "ojou", "ojimi" ) return end if base.lemma == "jeden" then add_normal_decl(base, "", "jeden", "jedna", "jedno", "jedni", "jedny", "jedného", "jednej", "jedných", "jednému", "jednej", "jedným", "jednu", "jednom", "jednej", "jedných", "jedným", "jednou", "jednými" ) return end if base.lemma == "všetok" then add_normal_decl(base, "", "všetok", "všetka", "všetko", "všetci", "všetky", "všetkého", "všetkej", "všetkých", "všetkému", "všetkej", "všetkým", "všetku", "všetkom", "všetkej", "všetkých", "všetkým", "všetkou", "všetkými" ) return end -- determiner like [[ten]], [[tamten]], [[onen]] stem, suffix = rmatch(base.lemma, "^(.*)(en)$") if stem then local nom_stem = stem .. suffix add_normal_decl(base, nom_stem, "") add_normal_decl(base, stem, nil, "á", "o", "í", "ie", "oho", "ej", "ých", "omu", "ej", "ým", "ú", "om", "ej", "ých", "ým", "ou", "ými" ) return end if base.lemma == "tento" then add_normal_decl(base, "", "tento", "táto", "toto", "títo", "tieto", "tohto", "tejto", "týchto", "tomuto", "tejto", "týmto", "tuto", "tomto", "tejto", "týchto", "týmto", "touto", "týmito" ) return end if base.lemma == "všetok" then add_normal_decl(base, nom_stem, "") add_normal_decl(base, stem, nil, "á", "o", "í", "ie", "oh", "ej", "ých", "omu", "ej", "ým", "ú", "om", "ej", "ých", "ým", "ou", "ými" ) return end -- [[náš]], [[váš]] stem, suffix = rmatch(base.lemma, "^(.*)(áš)$") if stem then add_normal_decl(base, stem, "áš", "aša", "aše", "aši", "aše", "ášho", "ašej", "ašich", "ášmu", "ašej", "ašim", "ašu", "ašom", "ašej", "ašich", "aším", "ašou", "ašimi" ) return end if base.lemma == "sám" then add_normal_decl(base, "sám", "") add_normal_decl(base, "sam", nil, "a", "o", "i", "y", "ého", "ej", "ých", "ému", "ej", "ým", "u", "om", "ej", "ých", "ým", "ou", "ými" ) return end error("Unrecognized irregular lemma '" .. base.lemma .. "'") end local function fetch_footnotes(separated_group) local footnotes for j = 2, #separated_group - 1, 2 do if separated_group[j + 1] ~= "" then error("Extraneous text after bracketed footnotes: '" .. table.concat(separated_group) .. "'") end if not footnotes then footnotes = {} end table.insert(footnotes, separated_group[j]) end return footnotes end local function parse_indicator_spec(angle_bracket_spec) local inside = rmatch(angle_bracket_spec, "^<(.*)>$") assert(inside) local base = {forms = {}} if inside ~= "" then local parts = rsplit(inside, ".", true) for _, part in ipairs(parts) do if part == "irreg" then base.irreg = true elseif part == "short" then base.short = {{ base = { form = "+", }, stem = { form = "+", } }} elseif rfind(part, "^short:") then part = rsub(part, "^short:%s*", "") base.short = {} local segments = put.parse_balanced_segment_run(part, "[", "]") local comma_separated_groups = put.split_alternating_runs(segments, "%s*,%s*") for _, comma_separated_group in ipairs(comma_separated_groups) do if comma_separated_group[1] == "*" then -- reducible table.insert(base.short, { base = { form = "*", footnotes = fetch_footnotes(comma_separated_group), }, stem = { form = "*", footnotes = fetch_footnotes(comma_separated_group), } }) else local slash_separated_groups = put.split_alternating_runs(comma_separated_group, "%s*/%s*") if #slash_separated_groups > 2 then error("Too many slash-separated stems: '" .. inside .. "'") end local short_base = slash_separated_groups[1] local short_stem = slash_separated_groups[2] local short_base_obj = { form = short_base[1], footnotes = fetch_footnotes(short_base), } local short_stem_obj if short_stem then short_stem_obj = { form = short_stem[1], footnotes = fetch_footnotes(short_stem), } end table.insert(base.short, { base = short_base_obj, stem = short_stem_obj, }) end iut.insert_form(forms, slot, formobj) end else error("Unrecognized indicator '" .. part .. "': '" .. inside .. "'") end end end return base end local function normalize_all_lemmas(alternant_multiword_spec, pagename) iut.map_word_specs(alternant_multiword_spec, function(base) if base.lemma == "" then base.lemma = pagename end base.orig_lemma = base.lemma base.orig_lemma_no_links = m_links.remove_links(base.lemma) base.lemma = base.orig_lemma_no_links end) end local function detect_indicator_spec(base) if base.short then if not base.lemma:find("ý$") then error("Short forms can only be specified for lemmas ending in -ý, but saw '" .. base.lemma .. "'") end local stem = rmatch(base.lemma, "^(.*)ý$") for _, short_spec in ipairs(base.short) do if short_spec.base.form == "+" then short_spec.base.form = stem elseif short_spec.base.form == "*" then short_spec.base.form = com.dereduce(base, stem) if not short_spec.base.form then error("Unable to construct non-reduced variant of stem '" .. stem .. "'") end end if not short_spec.stem then short_spec.stem = { form = short_spec.base.form, footnotes = short_spec.base.footnotes } end if short_spec.stem.form == "+" or short_spec.stem.form == "*" then short_spec.stem.form = stem end end end if base.irreg then base.decl = "irreg" else base.decl = "normal" end end local function detect_all_indicator_specs(alternant_multiword_spec) iut.map_word_specs(alternant_multiword_spec, function(base) detect_indicator_spec(base) end) end local function decline_adjective(base) if not decls[base.decl] then error("Internal error: Unrecognized declension type '" .. base.decl .. "'") end decls[base.decl](base) -- handle_derived_slots_and_overrides(base) end -- Process override for the arguments in `args`, storing the results into `forms`. If `do_acc`, only do accusative -- slots; otherwise, don't do accusative slots. local function process_overrides(forms, args, do_acc) for slot, _ in pairs(input_adjective_slots) do if args[slot] and not not do_acc == not not slot:find("^acc") then forms[slot] = nil if args[slot] ~= "-" and args[slot] ~= "—" then local segments = put.parse_balanced_segment_run(args[slot], "[", "]") local comma_separated_groups = put.split_alternating_runs(segments, "%s*,%s*") for _, comma_separated_group in ipairs(comma_separated_groups) do local formobj = { form = comma_separated_group[1], footnotes = fetch_footnotes(comma_separated_group), } iut.insert_form(forms, slot, formobj) end end end end end local function check_allowed_overrides(alternant_multiword_spec, args) local special = alternant_multiword_spec.special or alternant_multiword_spec.surname and "surname" or "" for slot, types in pairs(input_adjective_slots) do if args[slot] then local allowed = false for _, typ in ipairs(types) do if typ == special then allowed = true break end end if not allowed then error(("Override %s= not allowed for %s"):format(slot, special == "" and "regular declension" or "special=" .. special)) end end end end local function set_accusative(alternant_multiword_spec) local forms = alternant_multiword_spec.forms local function copy_if(from_slot, to_slot) if not forms[to_slot] then iut.insert_forms(forms, to_slot, forms[from_slot]) end end copy_if("nom_n", "acc_n") copy_if("gen_mn", "acc_m_an") copy_if("nom_m", "acc_m_in") copy_if("gen_p", "acc_mp_an") copy_if("nom_mp_in", "acc_mp_in") copy_if("nom_fnp", "acc_fnp") end local function add_categories(alternant_multiword_spec) local cats = {} local plpos = require(en_utilities_module).pluralize(alternant_multiword_spec.pos or "adjective") local function insert(cattype) -- m_table.insertIfNot(cats, "Slovak " .. cattype .. " " .. plpos) end if not alternant_multiword_spec.manual then iut.map_word_specs(alternant_multiword_spec, function(base) if base.decl == "irreg" then insert("irregular") elseif rfind(base.lemma, "ý$") then insert("hard long") elseif rfind(base.lemma, "y$") then insert("hard short") elseif rfind(base.lemma, "í$") then insert("soft long") elseif rfind(base.lemma, "i$") then insert("soft short") else insert("possessive") end if base.short then -- table.insert(cats, "ဝေါဟာသလဝ်ဝေန်နဳယျာ" .. plpos .. "မၞုံဗီုပြၚ်ဂၠေံဂၠေံဂမၠိုၚ်") end end) end alternant_multiword_spec.categories = cats end local function show_forms(alternant_multiword_spec) local lemmas = {} local lemmaform = alternant_multiword_spec.forms.nom_m or alternant_multiword_spec.forms.nom_mp or alternant_multiword_spec.forms.nom_mp_an if lemmaform then for _, form in ipairs(lemmaform) do table.insert(lemmas, form.form) end end local props = { lemmas = lemmas, slot_table = get_output_adjective_slots(alternant_multiword_spec), lang = lang, } iut.show_forms(alternant_multiword_spec.forms, props) end local function make_table(alternant_multiword_spec) local forms = alternant_multiword_spec.forms local function template_prelude() return mw.getCurrentFrame():expandTemplate{ title = 'inflection-table-top', args = { title = '{title}{annotation}', palette = 'blue', tall = 'yes', } } end local function template_postlude() return mw.getCurrentFrame():expandTemplate{ title = 'inflection-table-bottom', args = { notes = '{notes_clause}' or nil } } end local table_spec_sg = [=[ ! colspan=5 class="outer" | ကိုန်ဨကဝုစ် |- ! rowspan="2" | ! colspan="2" | ပုလ္လိၚ် ! rowspan="2" | ဣတ္တိလိၚ် ! rowspan="2" | နပုလ္လိၚ် |- ! class="secondary" | လမျီုလုပ်ကၠုၚ် ! class="secondary" | မသက္ကုဟၟဲကဵုလမျီု |- ! မဒုၚ်ယၟု | colspan=2 | {nom_m} | {nom_f} | {nom_n} |- ! ဗဳဇဂကူ | colspan=2 | {gen_mn} | {gen_f} | {gen_mn} |- ! ပြကမ္မကာရက | colspan=2 | {dat_mn} | {dat_f} | {dat_mn} |- ! ကမ္မကာရက | {acc_m_an} | {acc_m_in} | {acc_f} | {acc_n} |- ! ခၞံဗဒှ်ဌာန်မတန်တဴ | colspan=2 | {loc_mn} | {loc_f} | {loc_mn} |- ! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက် | colspan=2 | {ins_mn} | {ins_f} | {ins_mn}{short_sg_clause} ]=] local table_spec_pl = [=[ ! colspan=5 class="outer" | ကိုန်ဗဟုဝစ် |- ! rowspan="2" | ! colspan="2" | ပုလ္လိၚ် ! colspan="2" rowspan="2" | ဣတ္တိလိၚ်/နပုလ္လိၚ် |- ! class="secondary" | <abbr title="ပူဂဵုပုလ္လိၚ်">virile</abbr> ! class="secondary" | <abbr title="ပုလ္လိၚ်မသက္ကုဟၟဲကဵုလမျီု ဝါ မသက္ကုဟၟဲကဵုလမျီု">nonvirile</abbr> |- ! မဒုၚ်ယၟု | {nom_mp_an} | colspan=3 | {nom_fnp} |- ! ဗဳဇဂကူ | colspan=4 | {gen_p} |- ! ပြကမ္မကာရက | colspan=4 | {dat_p} |- ! ကမ္မကာရက | {acc_mp_an} | colspan=3 | {acc_fnp} |- ! ခၞံဗဒှ်ဌာန်မတန်တဴ | colspan=4 | {loc_p} |- ! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက် | colspan=4 | {ins_p}{short_pl_clause} ]=] local table_spec = template_prelude("55") .. table_spec_sg .. "|-\n" .. table_spec_pl .. template_postlude() local table_spec_plonly = template_prelude("55") .. table_spec_pl .. template_postlude() local table_spec_numeral = template_prelude("40") .. [=[ ! colspan=5 class="outer" | ကိုန်ဗဟုဝစ် |- ! rowspan="2" colspan="2" | ! colspan="2" | ပုလ္လိၚ် ! rowspan="2" | ဣတ္တိလိၚ်/နပုလ္လိၚ် |- ! class="secondary" | လမျီုလုပ်ကၠုၚ် ! class="secondary" | မသက္ကုဟၟဲကဵုလမျီု |- ! colspan="2" | မဒုၚ်ယၟု | {nom_mp_an} | {nom_mp_in} | {nom_fnp} |- ! colspan="2" | ဗဳဇဂကူ | colspan="3" | {gen_p} |- ! colspan="2" | ပြကမ္မကာရက | colspan="3" | {dat_p} |- ! colspan="2" | ကမ္မကာရက | {acc_mp_an} | {acc_mp_in} | {acc_fnp} |- ! colspan="2" | ခၞံဗဒှ်ဌာန်မတန်တဴ | colspan="3" | {loc_p} |- ! colspan="2" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက် | colspan="3" | {ins_p} ]=] .. template_postlude() local short_sg_template = [=[ |- ! ဓမၠေံ | colspan=2 | {short_m} | {short_f} | {short_n} ]=] local short_pl_template = [=[ |- ! ဓမၠေံ | {short_mp_an} | colspan=3 | {short_fnp}]=] local table_spec = template_prelude("55") .. table_spec_sg .. "|-\n" .. table_spec_pl .. template_postlude() local table_spec_plonly = template_prelude("55") .. table_spec_pl .. template_postlude() if alternant_multiword_spec.title then forms.title = alternant_multiword_spec.title else forms.title = 'မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <i lang="sk">' .. forms.lemma .. '</i>' end if alternant_multiword_spec.manual then forms.annotation = "" else local ann_parts = {} local decls = {} iut.map_word_specs(alternant_multiword_spec, function(base) if base.decl == "irreg" then m_table.insertIfNot(decls, "irregular") elseif rfind(base.lemma, "ý$") then m_table.insertIfNot(decls, "hard-long") elseif rfind(base.lemma, "y$") then m_table.insertIfNot(decls, "hard-short") elseif rfind(base.lemma, "í$") then m_table.insertIfNot(decls, "soft-long") elseif rfind(base.lemma, "i$") then m_table.insertIfNot(decls, "soft-short") else m_table.insertIfNot(decls, "possessive") end end) table.insert(ann_parts, table.concat(decls, " // ")) forms.annotation = " (" .. table.concat(ann_parts, ", ") .. ")" end forms.notes_clause = forms.footnote ~= "" and forms.footnote or "" forms.short_sg_clause = forms.short_m and forms.short_m ~= "—" and m_string_utilities.format(short_sg_template, forms) or "" forms.short_pl_clause = forms.short_mp_an and forms.short_mp_an ~= "—" and m_string_utilities.format(short_pl_template, forms) or "" return m_string_utilities.format( alternant_multiword_spec.special == "plonly" and table_spec_plonly or alternant_multiword_spec.special == "ဂၞန်သၚ်္ချာ" and table_spec_numeral or table_spec, forms ) end -- Externally callable function to parse and decline an adjective given -- user-specified arguments. Return value is WORD_SPEC, an object where the -- declined forms are in `WORD_SPEC.forms` for each slot. If there are no values -- for a slot, the slot key will be missing. The value for a given slot is a -- list of objects {form=FORM, footnotes=FOOTNOTES}. function export.do_generate_forms(parent_args, pos, from_headword, def) local params = { [1] = {template_default = "pekný"}, pos = true, json = {type = "boolean"}, -- for use with bots title = true, pagename = true, } for slot, _ in pairs(input_adjective_slots) do params[slot] = true end -- Only default param 1 when displaying the template. local args = require("Module:parameters").process(parent_args, params) local pagename = args.pagename or mw.loadData("Module:headword/data").pagename local args1 = args[1] or pagename local parse_props = { parse_indicator_spec = parse_indicator_spec, allow_default_indicator = true, allow_blank_lemma = true, } local alternant_multiword_spec = iut.parse_inflected_text(args1, parse_props) alternant_multiword_spec.pos = args.pos alternant_multiword_spec.title = args.title alternant_multiword_spec.forms = {} normalize_all_lemmas(alternant_multiword_spec, pagename) detect_all_indicator_specs(alternant_multiword_spec) check_allowed_overrides(alternant_multiword_spec, args) local inflect_props = { slot_table = get_output_adjective_slots(alternant_multiword_spec), inflect_word_spec = decline_adjective, } iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props) -- Do non-accusative overrides so they get copied to the accusative forms appropriately. process_overrides(alternant_multiword_spec.forms, args) set_accusative(alternant_multiword_spec) -- Do accusative overrides after copying the accusative forms. process_overrides(alternant_multiword_spec.forms, args, "do acc") add_categories(alternant_multiword_spec) if args.json and not from_headword then return require("Module:JSON").toJSON(alternant_multiword_spec) end return alternant_multiword_spec end -- Externally callable function to parse and decline an adjective where all -- forms are given manually. Return value is WORD_SPEC, an object where the -- declined forms are in `WORD_SPEC.forms` for each slot. If there are no values -- for a slot, the slot key will be missing. The value for a given slot is a -- list of objects {form=FORM, footnotes=FOOTNOTES}. function export.do_generate_forms_manual(parent_args, pos, from_headword, def) local params = { pos = true, special = true, json = {type = "boolean"}, -- for use with bots title = true, } for slot, _ in pairs(input_adjective_slots) do params[slot] = true end local args = require("Module:parameters").process(parent_args, params) local alternant_multiword_spec = { pos = args.pos, special = args.special, title = args.title, forms = {}, manual = true, } check_allowed_overrides(alternant_multiword_spec, args) -- Do non-accusative overrides so they get copied to the accusative forms appropriately. process_overrides(alternant_multiword_spec.forms, args) set_accusative(alternant_multiword_spec) -- Do accusative overrides after copying the accusative forms. process_overrides(alternant_multiword_spec.forms, args, "do acc") add_categories(alternant_multiword_spec) if args.json and not from_headword then return require("Module:JSON").toJSON(alternant_multiword_spec) end return alternant_multiword_spec end -- Entry point for {{sk-adecl}}. Template-callable function to parse and decline -- an adjective given user-specified arguments and generate a displayable table -- of the declined forms. function export.show(frame) local parent_args = frame:getParent().args local alternant_multiword_spec = export.do_generate_forms(parent_args) show_forms(alternant_multiword_spec) return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang) end -- Entry point for {{sk-adecl-manual}}. Template-callable function to parse and -- decline an adjective given manually-specified inflections and generate a -- displayable table of the declined forms. function export.show_manual(frame) local parent_args = frame:getParent().args local alternant_multiword_spec = export.do_generate_forms_manual(parent_args) show_forms(alternant_multiword_spec) return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang) end return export edoiln0lw8u6je4pixsng2d8m08h6lt မဝ်ဂျူ:sk-adjective/doc 828 295622 396274 2026-06-04T04:00:59Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|sk}} </includeonly>" 396274 wikitext text/x-wiki {{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|sk}} </includeonly> 1ptj20p1jycujtsvk2if0j3dwu8uli4 ထာမ်ပလိက်:sv-noun-unc-irreg-c 10 295623 396278 2026-06-04T04:25:45Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|warn}}<!-- Validate template parameters --><noinclude>{{tcat|ndecl:noun-unc-irreg-c}} ==Usage== * <tt><nowiki>{{sv-noun-unc-irreg-c}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|tro}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|2=tron}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|tro|tron}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|2=majsen|3=majs}}</nowiki></tt> * <tt..." 396278 wikitext text/x-wiki {{#invoke:checkparams|warn}}<!-- Validate template parameters --><noinclude>{{tcat|ndecl:noun-unc-irreg-c}} ==Usage== * <tt><nowiki>{{sv-noun-unc-irreg-c}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|tro}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|2=tron}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|tro|tron}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|2=majsen|3=majs}}</nowiki></tt> * <tt><nowiki>{{sv-noun-unc-irreg-c|majs|majsen|majs|majsens}}</nowiki></tt> * For [[diplomati]]: <tt><nowiki>{{sv-noun-unc-irreg-c|ien=1}}</nowiki></tt> ==Categories== * [[:ကဏ္ဍ:နာမ်သွဳဒေန်ဂမၠိုၚ်|Swedish nouns]] ==Output== </noinclude>{{sv-decl-noun<!-- -->|uncountable=yes<!-- -->|definitions={{{definitions|}}}<!-- -->| {{{1<includeonly>|{{pagename}}</includeonly>}}}<!-- -->| {{#if:{{{ien|}}}|[[{{{2<includeonly>|{{pagename}}n</includeonly>}}}]]<br />{{qualifier|dated}}&nbsp;[[{{pagename}}en]]|{{{2<includeonly>|{{pagename}}n</includeonly>}}}}}<!-- -->| -<!-- -->| -<!-- -->| {{{3<includeonly>|{{{1|{{pagename}}}}}s</includeonly>}}}<!-- -->| {{#if:{{{ien|}}}|[[{{{4<includeonly>|{{{2|{{pagename}}n}}}s</includeonly>}}}]]<br />{{qualifier|dated}}&nbsp;[[{{pagename}}ens]]|{{{4<includeonly>|{{{2|{{pagename}}n}}}s</includeonly>}}}}}<!-- -->| -<!-- -->| -<!-- -->}}<!-- -->{{#ifeq:{{NAMESPACE}}||[[ကဏ္ဍ:နာမ်သွဳဒေန်ဂမၠိုၚ်]]}} 5iazxppzjjgdzi6849ykr42wvfqa8hi ထာမ်ပလိက်:tr-infl-noun-c 10 295624 396279 2026-06-04T04:27:17Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:tr-nouns|cons}}{{#if:{{{stem|}}}|{{#ifeq:{{NAMESPACE}}||<includeonly></includeonly>}}}}<noinclude>{{documentation}}</noinclude>" 396279 wikitext text/x-wiki {{#invoke:tr-nouns|cons}}{{#if:{{{stem|}}}|{{#ifeq:{{NAMESPACE}}||<includeonly></includeonly>}}}}<noinclude>{{documentation}}</noinclude> du77ioordwref5hso6jekbdf6zynm60 မဝ်ဂျူ:tr-nouns 828 295625 396280 2026-06-04T04:47:54Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "local lang = require("Module:languages").getByCode("tr") local export = {} local vowels = { ["a"] = {high = "ı", low = "a"}, ["â"] = {high = "ı", low = "a"}, ["e"] = {high = "i", low = "e"}, ["ı"] = {high = "ı", low = "a"}, ["i"] = {high = "i", low = "e"}, ["î"] = {high = "i", low = "e"}, ["o"] = {high = "u", low = "a"}, ["ö"] = {high = "ü", low = "e"}, ["u"] = {high = "u", low = "a"}, ["û"] = {high..." 396280 Scribunto text/plain local lang = require("Module:languages").getByCode("tr") local export = {} local vowels = { ["a"] = {high = "ı", low = "a"}, ["â"] = {high = "ı", low = "a"}, ["e"] = {high = "i", low = "e"}, ["ı"] = {high = "ı", low = "a"}, ["i"] = {high = "i", low = "e"}, ["î"] = {high = "i", low = "e"}, ["o"] = {high = "u", low = "a"}, ["ö"] = {high = "ü", low = "e"}, ["u"] = {high = "u", low = "a"}, ["û"] = {high = "u", low = "a"}, ["ü"] = {high = "ü", low = "e"}, } -- Inflection functions function export.vowel(frame) local params = { [1] = {required = true, default = "u"}, ["n"] = {}, ["poss"] = {type = "boolean"}, ["pred"] = {type = "boolean"}, ["json"] = {type = "boolean"}, } local args = require("Module:parameters").process(frame:getParent().args, params) local stem = mw.loadData("Module:headword/data").pagename local data = {forms = {}, info = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. stem .. "''", categories = {}} local vowel = vowels[args[1]] local plvowel = vowels[vowel.low] local plstem if args["n"] == "p" then plstem = stem else plstem = stem .. "l" .. vowel.low .. "r" end if mw.ustring.match(stem, "([aâeıiîoöuûü])$") ~= args[1] then require("Module:debug").track("tr-nouns/vowel") end data.forms["nom|s"] = {stem} data.forms["def|acc|s"] = {stem .. "y" .. vowel.high} data.forms["dat|s"] = {stem .. "y" .. vowel.low} data.forms["loc|s"] = {stem .. "d" .. vowel.low} data.forms["abl|s"] = {stem .. "d" .. vowel.low .. "n"} data.forms["gen|s"] = {stem .. "n" .. vowel.high .. "n"} data.forms["nom|p"] = {plstem} data.forms["def|acc|p"] = {plstem .. plvowel.high} data.forms["dat|p"] = {plstem .. plvowel.low} data.forms["loc|p"] = {plstem .. "d" .. plvowel.low} data.forms["abl|p"] = {plstem .. "d" .. plvowel.low .. "n"} data.forms["gen|p"] = {plstem .. plvowel.high .. "n"} if args["poss"] then data.forms["1|s|spos|poss"] = {stem .. "m"} data.forms["2|s|spos|poss"] = {stem .. "n"} data.forms["3|s|spos|poss"] = {stem .. "s" .. vowel.high} data.forms["1|p|spos|poss"] = {stem .. "m" .. vowel.high .. "z"} data.forms["2|p|spos|poss"] = {stem .. "n" .. vowel.high .. "z"} data.forms["3|p|spos|poss"] = {plstem .. plvowel.high} data.forms["1|s|mpos|poss"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|mpos|poss"] = {plstem .. plvowel.high .. "n"} data.forms["3|s|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|p|mpos|poss"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z"} data.forms["2|p|mpos|poss"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|s|spos|poss|def|acc"] = {stem .. "m" .. vowel.high} data.forms["2|s|spos|poss|def|acc"] = {stem .. "n" .. vowel.high} data.forms["3|s|spos|poss|def|acc"] = {stem .. "s" .. vowel.high .. "n" .. vowel.high} data.forms["1|p|spos|poss|def|acc"] = {stem .. "m" .. vowel.high .. "z" .. vowel.high} data.forms["2|p|spos|poss|def|acc"] = {stem .. "n" .. vowel.high .. "z" .. vowel.high} data.forms["3|p|spos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high} data.forms["2|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["3|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high} data.forms["2|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high} data.forms["3|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|spos|poss|dat"] = {stem .. "m" .. vowel.low} data.forms["2|s|spos|poss|dat"] = {stem .. "n" .. vowel.low} data.forms["3|s|spos|poss|dat"] = {stem .. "s" .. vowel.high .. "n" .. vowel.low} data.forms["1|p|spos|poss|dat"] = {stem .. "m" .. vowel.high .. "z" .. vowel.low} data.forms["2|p|spos|poss|dat"] = {stem .. "n" .. vowel.high .. "z" .. vowel.low} data.forms["3|p|spos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.low} data.forms["2|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["3|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.low} data.forms["2|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.low} data.forms["3|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|spos|poss|loc"] = {stem .. "m" .. "d" .. vowel.low} data.forms["2|s|spos|poss|loc"] = {stem .. "n" .. "d" .. vowel.low} data.forms["3|s|spos|poss|loc"] = {stem .. "s" .. vowel.high .. "n" .. "d" .. vowel.low} data.forms["1|p|spos|poss|loc"] = {stem .. "m" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["2|p|spos|poss|loc"] = {stem .. "n" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["3|p|spos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low} data.forms["2|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["3|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["2|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["3|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|spos|poss|abl"] = {stem .. "m" .. "d" .. vowel.low .. "n"} data.forms["2|s|spos|poss|abl"] = {stem .. "n" .. "d" .. vowel.low .. "n"} data.forms["3|s|spos|poss|abl"] = {stem .. "s" .. vowel.high .. "n" .. "d" .. vowel.low .. "n"} data.forms["1|p|spos|poss|abl"] = {stem .. "m" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["2|p|spos|poss|abl"] = {stem .. "n" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["3|p|spos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low .. "n"} data.forms["2|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["3|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["2|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["3|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|spos|poss|gen"] = {stem .. "m" .. vowel.high .. "n"} data.forms["2|s|spos|poss|gen"] = {stem .. "n" .. vowel.high .. "n"} data.forms["3|s|spos|poss|gen"] = {stem .. "s" .. vowel.high .. "n" .. vowel.high .. "n"} data.forms["1|p|spos|poss|gen"] = {stem .. "m" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["2|p|spos|poss|gen"] = {stem .. "n" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["3|p|spos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "n"} data.forms["2|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["3|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["2|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["3|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} end if args["pred"] then data.forms["1|s|pred|of the|s"] = {stem .. "y" .. vowel.high .. "m"} data.forms["2|s|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n"} data.forms["3|s|pred|of the|s"] = {stem, stem .. "d" .. vowel.high .. "r"} data.forms["1|p|pred|of the|s"] = {stem .. "y" .. vowel.high .. "z"} data.forms["2|p|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n" .. vowel.high .. "z"} data.forms["3|p|pred|of the|s"] = {plstem} data.forms["1|s|pred|of the|p"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|pred|of the|p"] = {plstem .. "s" .. plvowel.high .. "n"} data.forms["3|s|pred|of the|p"] = {plstem, plstem .. "d" .. plvowel.high .. "r"} data.forms["1|p|pred|of the|p"] = {plstem .. plvowel.high .. "z"} data.forms["2|p|pred|of the|p"] = {plstem .. "s" .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|pred|of the|p"] = {plstem .. "d" .. plvowel.high .. "r"} end postprocess(args, data) if args["json"] then return mw.text.jsonEncode(data) end return make_table(data) end function export.cons(frame) local params = { [1] = {required = true, default = "u"}, ["n"] = {}, ["poss"] = {type = "boolean"}, ["pred"] = {type = "boolean"}, ["stem"] = {}, ["json"] = {type = "boolean"}, } local args = require("Module:parameters").process(frame:getParent().args, params) local stem = mw.loadData("Module:headword/data").pagename local data = {forms = {}, info = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. stem .. "''", categories = {}} local stem2 = args["stem"] or stem local vowel = vowels[args[1]] local plvowel = vowels[vowel.low] local plstem if args["n"] == "p" then plstem = stem else plstem = stem .. "l" .. vowel.low .. "r" end if mw.ustring.match(stem, "([aâeıiîoöuûü])[^aâeıiîoöuûü]+$") ~= args[1] then require("Module:debug").track("tr-nouns/vowel") end local dt = "d" if mw.ustring.find(stem, "[çfhkptsş]$") then dt = "t" end data.forms["nom|s"] = {stem} data.forms["def|acc|s"] = {stem2 .. vowel.high} data.forms["dat|s"] = {stem2 .. vowel.low} data.forms["loc|s"] = {stem .. dt .. vowel.low} data.forms["abl|s"] = {stem .. dt .. vowel.low .. "n"} data.forms["gen|s"] = {stem2 .. vowel.high .. "n"} data.forms["nom|p"] = {plstem} data.forms["def|acc|p"] = {plstem .. plvowel.high} data.forms["dat|p"] = {plstem .. plvowel.low} data.forms["loc|p"] = {plstem .. "d" .. plvowel.low} data.forms["abl|p"] = {plstem .. "d" .. plvowel.low .. "n"} data.forms["gen|p"] = {plstem .. plvowel.high .. "n"} if args["poss"] then data.forms["1|s|spos|poss"] = {stem2 .. vowel.high .. "m"} data.forms["2|s|spos|poss"] = {stem2 .. vowel.high .. "n"} data.forms["3|s|spos|poss"] = {stem2 .. vowel.high} data.forms["1|p|spos|poss"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z"} data.forms["2|p|spos|poss"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z"} data.forms["3|p|spos|poss"] = {plstem .. plvowel.high} data.forms["1|s|mpos|poss"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|mpos|poss"] = {plstem .. plvowel.high .. "n"} data.forms["3|s|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|p|mpos|poss"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z"} data.forms["2|p|mpos|poss"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|s|spos|poss|def|acc"] = {stem2 .. vowel.high .. "m" .. vowel.high} data.forms["2|s|spos|poss|def|acc"] = {stem2 .. vowel.high .. "n" .. vowel.high} data.forms["3|s|spos|poss|def|acc"] = {stem2 .. vowel.high .. "n" .. vowel.high} data.forms["1|p|spos|poss|def|acc"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z" .. vowel.high} data.forms["2|p|spos|poss|def|acc"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z" .. vowel.high} data.forms["3|p|spos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high} data.forms["2|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["3|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high} data.forms["2|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high} data.forms["3|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|spos|poss|dat"] = {stem2 .. vowel.high .. "m" .. vowel.low} data.forms["2|s|spos|poss|dat"] = {stem2 .. vowel.high .. "n" .. vowel.low} data.forms["3|s|spos|poss|dat"] = {stem2 .. vowel.high .. "n" .. vowel.low} data.forms["1|p|spos|poss|dat"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z" .. vowel.low} data.forms["2|p|spos|poss|dat"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z" .. vowel.low} data.forms["3|p|spos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.low} data.forms["2|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["3|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.low} data.forms["2|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.low} data.forms["3|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|spos|poss|loc"] = {stem2 .. vowel.high .. "m" .. "d" .. vowel.low} data.forms["2|s|spos|poss|loc"] = {stem2 .. vowel.high .. "n" .. "d" .. vowel.low} data.forms["3|s|spos|poss|loc"] = {stem2 .. vowel.high .. "n" .. "d" .. vowel.low} data.forms["1|p|spos|poss|loc"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["2|p|spos|poss|loc"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["3|p|spos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low} data.forms["2|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["3|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["2|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["3|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|spos|poss|abl"] = {stem2 .. vowel.high .. "m" .. "d" .. vowel.low .. "n"} data.forms["2|s|spos|poss|abl"] = {stem2 .. vowel.high .. "n" .. "d" .. vowel.low .. "n"} data.forms["3|s|spos|poss|abl"] = {stem2 .. vowel.high .. "n" .. "d" .. vowel.low .. "n"} data.forms["1|p|spos|poss|abl"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["2|p|spos|poss|abl"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["3|p|spos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low .. "n"} data.forms["2|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["3|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["2|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["3|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|spos|poss|gen"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "n"} data.forms["2|s|spos|poss|gen"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "n"} data.forms["3|s|spos|poss|gen"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "n"} data.forms["1|p|spos|poss|gen"] = {stem2 .. vowel.high .. "m" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["2|p|spos|poss|gen"] = {stem2 .. vowel.high .. "n" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["3|p|spos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "n"} data.forms["2|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["3|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["2|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["3|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} end if args["pred"] then data.forms["1|s|pred|of the|s"] = {stem2 .. vowel.high .. "m"} data.forms["2|s|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n"} data.forms["3|s|pred|of the|s"] = {stem, stem .. dt .. vowel.high .. "r"} data.forms["1|p|pred|of the|s"] = {stem2 .. vowel.high .. "z"} data.forms["2|p|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n" .. vowel.high .. "z"} data.forms["3|p|pred|of the|s"] = {plstem} data.forms["1|s|pred|of the|p"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|pred|of the|p"] = {plstem .. "s" .. plvowel.high .. "n"} data.forms["3|s|pred|of the|p"] = {plstem, plstem .. "d" .. plvowel.high .. "r"} data.forms["1|p|pred|of the|p"] = {plstem .. plvowel.high .. "z"} data.forms["2|p|pred|of the|p"] = {plstem .. "s" .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|pred|of the|p"] = {plstem .. "d" .. plvowel.high .. "r"} end postprocess(args, data) if args["json"] then return mw.text.jsonEncode(data) end return make_table(data) end function export.compound(frame) local params = { [1] = {required = true, default = "u"}, ["n"] = {}, ["poss"] = {}, ["pred"] = {type = "boolean"}, ["stem"] = {}, ["json"] = {type = "boolean"}, } local args = require("Module:parameters").process(frame:getParent().args, params) local stem = mw.loadData("Module:headword/data").pagename local data = {forms = {}, info = "မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''" .. stem .. "''", categories = {}} local stem2 = args["stem"] or stem local vowel = vowels[args[1]] local plvowel = vowels[vowel.low] local plstem if args["n"] == "p" then plstem = stem2 else plstem = stem2 .. "l" .. vowel.low .. "r" end if mw.ustring.match(stem, "([aâeıiîoöuûü])$") ~= args[1] then require("Module:debug").track("tr-nouns/vowel") end local dt = "d" if mw.ustring.find(stem2, "[çfhkptsş]$") then dt = "t" end data.forms["nom|s"] = {stem} data.forms["def|acc|s"] = {stem .. "n" .. vowel.high} data.forms["dat|s"] = {stem .. "n" .. vowel.low} data.forms["loc|s"] = {stem .. "nd" .. vowel.low} data.forms["abl|s"] = {stem .. "nd" .. vowel.low .. "n"} data.forms["gen|s"] = {stem .. "n" .. vowel.high .. "n"} data.forms["nom|p"] = {plstem .. plvowel.high} data.forms["def|acc|p"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["dat|p"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["loc|p"] = {plstem .. plvowel.high .. "nd" .. plvowel.low} data.forms["abl|p"] = {plstem .. plvowel.high .. "nd" .. plvowel.low .. "n"} data.forms["gen|p"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} if args["poss"] then if args["poss"] == "c" then data.forms["1|s|spos|poss"] = {stem .. "m"} data.forms["2|s|spos|poss"] = {stem .. "n"} data.forms["3|s|spos|poss"] = {stem} data.forms["1|p|spos|poss"] = {stem .. "m" .. vowel.high .. "z"} data.forms["2|p|spos|poss"] = {stem .. "n" .. vowel.high .. "z"} data.forms["3|p|spos|poss"] = {plstem .. plvowel.high} data.forms["1|s|mpos|poss"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|mpos|poss"] = {plstem .. plvowel.high .. "n"} data.forms["3|s|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|p|mpos|poss"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z"} data.forms["2|p|mpos|poss"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|s|spos|poss|def|acc"] = {stem .. "m" .. vowel.high} data.forms["2|s|spos|poss|def|acc"] = {stem .. "n" .. vowel.high} data.forms["3|s|spos|poss|def|acc"] = {stem .. "n" .. vowel.high} data.forms["1|p|spos|poss|def|acc"] = {stem .. "m" .. vowel.high .. "z" .. vowel.high} data.forms["2|p|spos|poss|def|acc"] = {stem .. "n" .. vowel.high .. "z" .. vowel.high} data.forms["3|p|spos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high} data.forms["2|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["3|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high} data.forms["2|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high} data.forms["3|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|spos|poss|dat"] = {stem .. "m" .. vowel.low} data.forms["2|s|spos|poss|dat"] = {stem .. "n" .. vowel.low} data.forms["3|s|spos|poss|dat"] = {stem .. "n" .. vowel.low} data.forms["1|p|spos|poss|dat"] = {stem .. "m" .. vowel.high .. "z" .. vowel.low} data.forms["2|p|spos|poss|dat"] = {stem .. "n" .. vowel.high .. "z" .. vowel.low} data.forms["3|p|spos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.low} data.forms["2|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["3|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.low} data.forms["2|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.low} data.forms["3|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|spos|poss|loc"] = {stem .. "m" .. "d" .. vowel.low} data.forms["2|s|spos|poss|loc"] = {stem .. "n" .. "d" .. vowel.low} data.forms["3|s|spos|poss|loc"] = {stem .. "n" .. "d" .. vowel.low} data.forms["1|p|spos|poss|loc"] = {stem .. "m" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["2|p|spos|poss|loc"] = {stem .. "n" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["3|p|spos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low} data.forms["2|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["3|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["2|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["3|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|spos|poss|abl"] = {stem .. "m" .. "d" .. vowel.low .. "n"} data.forms["2|s|spos|poss|abl"] = {stem .. "n" .. "d" .. vowel.low .. "n"} data.forms["3|s|spos|poss|abl"] = {stem .. "n" .. "d" .. vowel.low .. "n"} data.forms["1|p|spos|poss|abl"] = {stem .. "m" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["2|p|spos|poss|abl"] = {stem .. "n" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["3|p|spos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low .. "n"} data.forms["2|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["3|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["2|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["3|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|spos|poss|gen"] = {stem .. "m" .. vowel.high .. "n"} data.forms["2|s|spos|poss|gen"] = {stem .. "n" .. vowel.high .. "n"} data.forms["3|s|spos|poss|gen"] = {stem .. "n" .. vowel.high .. "n"} data.forms["1|p|spos|poss|gen"] = {stem .. "m" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["2|p|spos|poss|gen"] = {stem .. "n" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["3|p|spos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "n"} data.forms["2|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["3|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["2|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["3|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} elseif args["poss"] == "v" then data.forms["1|s|spos|poss"] = {stem2 .. "m"} data.forms["2|s|spos|poss"] = {stem2 .. "n"} data.forms["3|s|spos|poss"] = {stem2 .. "s" .. vowel.high} data.forms["1|p|spos|poss"] = {stem2 .. "m" .. vowel.high .. "z"} data.forms["2|p|spos|poss"] = {stem2 .. "n" .. vowel.high .. "z"} data.forms["3|p|spos|poss"] = {plstem .. plvowel.high} data.forms["1|s|mpos|poss"] = {plstem .. plvowel.high .. "m"} data.forms["2|s|mpos|poss"] = {plstem .. plvowel.high .. "n"} data.forms["3|s|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|p|mpos|poss"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z"} data.forms["2|p|mpos|poss"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|mpos|poss"] = {plstem .. plvowel.high} data.forms["1|s|spos|poss|def|acc"] = {stem2 .. "m" .. vowel.high} data.forms["2|s|spos|poss|def|acc"] = {stem2 .. "n" .. vowel.high} data.forms["3|s|spos|poss|def|acc"] = {stem2 .. "s" .. vowel.high .. "n" .. vowel.high} data.forms["1|p|spos|poss|def|acc"] = {stem2 .. "m" .. vowel.high .. "z" .. vowel.high} data.forms["2|p|spos|poss|def|acc"] = {stem2 .. "n" .. vowel.high .. "z" .. vowel.high} data.forms["3|p|spos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high} data.forms["2|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["3|s|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high} data.forms["2|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high} data.forms["3|p|mpos|poss|def|acc"] = {plstem .. plvowel.high .. "n" .. plvowel.high} data.forms["1|s|spos|poss|dat"] = {stem2 .. "m" .. vowel.low} data.forms["2|s|spos|poss|dat"] = {stem2 .. "n" .. vowel.low} data.forms["3|s|spos|poss|dat"] = {stem2 .. "s" .. vowel.high .. "n" .. vowel.low} data.forms["1|p|spos|poss|dat"] = {stem2 .. "m" .. vowel.high .. "z" .. vowel.low} data.forms["2|p|spos|poss|dat"] = {stem2 .. "n" .. vowel.high .. "z" .. vowel.low} data.forms["3|p|spos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.low} data.forms["2|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["3|s|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.low} data.forms["2|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.low} data.forms["3|p|mpos|poss|dat"] = {plstem .. plvowel.high .. "n" .. plvowel.low} data.forms["1|s|spos|poss|loc"] = {stem2 .. "m" .. "d" .. vowel.low} data.forms["2|s|spos|poss|loc"] = {stem2 .. "n" .. "d" .. vowel.low} data.forms["3|s|spos|poss|loc"] = {stem2 .. "s" .. vowel.high .. "n" .. "d" .. vowel.low} data.forms["1|p|spos|poss|loc"] = {stem2 .. "m" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["2|p|spos|poss|loc"] = {stem2 .. "n" .. vowel.high .. "z" .. "d" .. vowel.low} data.forms["3|p|spos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low} data.forms["2|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["3|s|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["2|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low} data.forms["3|p|mpos|poss|loc"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low} data.forms["1|s|spos|poss|abl"] = {stem2 .. "m" .. "d" .. vowel.low .. "n"} data.forms["2|s|spos|poss|abl"] = {stem2 .. "n" .. "d" .. vowel.low .. "n"} data.forms["3|s|spos|poss|abl"] = {stem2 .. "s" .. vowel.high .. "n" .. "d" .. vowel.low .. "n"} data.forms["1|p|spos|poss|abl"] = {stem2 .. "m" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["2|p|spos|poss|abl"] = {stem2 .. "n" .. vowel.high .. "z" .. "d" .. vowel.low .. "n"} data.forms["3|p|spos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. "d" .. plvowel.low .. "n"} data.forms["2|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["3|s|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["2|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. "d" .. plvowel.low .. "n"} data.forms["3|p|mpos|poss|abl"] = {plstem .. plvowel.high .. "n" .. "d" .. plvowel.low .. "n"} data.forms["1|s|spos|poss|gen"] = {stem2 .. "m" .. vowel.high .. "n"} data.forms["2|s|spos|poss|gen"] = {stem2 .. "n" .. vowel.high .. "n"} data.forms["3|s|spos|poss|gen"] = {stem2 .. "s" .. vowel.high .. "n" .. vowel.high .. "n"} data.forms["1|p|spos|poss|gen"] = {stem2 .. "m" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["2|p|spos|poss|gen"] = {stem2 .. "n" .. vowel.high .. "z" .. vowel.high .. "n"} data.forms["3|p|spos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "n"} data.forms["2|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["3|s|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} data.forms["1|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "m" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["2|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "z" .. plvowel.high .. "n"} data.forms["3|p|mpos|poss|gen"] = {plstem .. plvowel.high .. "n" .. plvowel.high .. "n"} else --error("For compound nouns, please specify |poss=c if the possessor is a consonant stem and |poss=v if it is a vowel stem.") table.insert(data.categories, "Turkish compound nouns with invalid poss parameter") end end if args["pred"] then data.forms["1|s|pred|of the|s"] = {stem .. "y" .. vowel.high .. "m"} data.forms["2|s|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n"} data.forms["3|s|pred|of the|s"] = {stem} data.forms["1|p|pred|of the|s"] = {stem .. "y" .. vowel.high .. "z"} data.forms["2|p|pred|of the|s"] = {stem .. "s" .. vowel.high .. "n" .. vowel.high .. "z"} data.forms["3|p|pred|of the|s"] = {plstem .. plvowel.high} data.forms["1|s|pred|of the|p"] = {plstem .. plvowel.high .. "y" .. plvowel.high .. "m"} data.forms["2|s|pred|of the|p"] = {plstem .. plvowel.high .. "s" .. plvowel.high .. "n"} data.forms["3|s|pred|of the|p"] = {plstem .. plvowel.high} data.forms["1|p|pred|of the|p"] = {plstem .. plvowel.high .. "y" .. plvowel.high .. "z"} data.forms["2|p|pred|of the|p"] = {plstem .. plvowel.high .. "s" .. plvowel.high .. "n" .. plvowel.high .. "z"} data.forms["3|p|pred|of the|p"] = {plstem .. plvowel.high} end postprocess(args, data) if args["json"] then return mw.text.jsonEncode(data) end return make_table(data) end function postprocess(args, data) data.has_poss = args["poss"] data.has_pred = args["pred"] data.n = args["n"] if args["n"] == "p" then table.insert(data.categories, "ကိုန်ဗဟုဝစ်" .. lang:getCanonicalName() .. "တၞးမကၠောန်စွံလဝ်ဂမၠိုၚ်") elseif args["n"] == "s" then table.insert(data.categories, "နာမ်" .. lang:getCanonicalName() .. "မတော်ဟွံဂွံဂမၠိုၚ်") elseif args["n"] then error("args= must be \"s\" or \"p\".") end for key, form in pairs(data.forms) do -- Do not show singular or plural forms for nominals that don't have them if (args["n"] == "p" and key:find("|s$")) or (args["n"] == "s" and key:find("|p$")) then form = nil end data.forms[key] = form end data.lemma = (data.forms["nom|" .. (data.n or "s")])[1] -- Check if the lemma form matches the page name if lang:stripDiacritics(data.lemma) ~= mw.loadData("Module:headword/data").pagename then table.insert(data.categories, lang:getCanonicalName() .. " entries with inflection not matching pagename") end end -- Make the table function make_table(data) local function repl(param) local accel = true local no_store = false if param == "info" then return mw.getContentLanguage():ucfirst(data.info or "") elseif string.sub(param, 1, 1) == "!" then no_store = true param = string.sub(param, 2) elseif string.sub(param, 1, 1) == "#" then accel = false param = string.sub(param, 2) end local forms = data.forms[param] if not forms then return "&mdash;" end local ret = {} for key, subform in ipairs(forms) do table.insert(ret, require("Module:links").full_link({lang = lang, term = subform, accel = accel and {form = param, lemma = data.lemma, no_store = no_store} or nil})) end return table.concat(ret, "<br/>") end local wikicode = {} if data.has_poss or data.has_pred then table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-box-top", args = { title = "{{{info}}}", flow = "vertical", } }) table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-top", args = { title = "-", palette = "red", } }) else table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-top", args = { title = "{{{info}}}", tall = "yes", palette = "red", } }) end table.insert(wikicode, [=[ ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! မဒုၚ်ယၟု | {{{nom|s}}} | {{{nom|p}}} |- ! ကမ္မကာရကမချိုတ်ပၠိုတ် | {{{def|acc|s}}} | {{{def|acc|p}}} |- ! ပြကမ္မကာရက | {{{dat|s}}} | {{{dat|p}}} |- ! ခၞံဗဒှ်ဌာန်မတန်တဴ | {{{loc|s}}} | {{{loc|p}}} |- ! ပရေၚ်မလၚ် | {{{abl|s}}} | {{{abl|p}}} |- ! ဗဳဇဂကူ | {{{gen|s}}} | {{{gen|p}}} ]=]) table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-bottom" }) -- Possessive forms if data.has_poss then table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-top", args = { title = "Possessive forms", palette = "red", tall = "yes", } }) table.insert(wikicode, [=[ ! colspan="3" class="outer" | မဒုၚ်ယၟု |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss}}} | {{{1|s|mpos|poss}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss}}} | {{{2|s|mpos|poss}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss}}} | {{{3|s|mpos|poss}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss}}} | {{{1|p|mpos|poss}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss}}} | {{{2|p|mpos|poss}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss}}} | {{{3|p|mpos|poss}}} |- ! colspan="3" class="outer" | ကမ္မကာရကမချိုတ်ပၠိုတ် |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss|def|acc}}} | {{{1|s|mpos|poss|def|acc}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss|def|acc}}} | {{{2|s|mpos|poss|def|acc}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss|def|acc}}} | {{{3|s|mpos|poss|def|acc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss|def|acc}}} | {{{1|p|mpos|poss|def|acc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss|def|acc}}} | {{{2|p|mpos|poss|def|acc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss|def|acc}}} | {{{3|p|mpos|poss|def|acc}}} |- ! colspan="3" class="outer" | ပြကမ္မကာရက |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss|dat}}} | {{{1|s|mpos|poss|dat}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss|dat}}} | {{{2|s|mpos|poss|dat}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss|dat}}} | {{{3|s|mpos|poss|dat}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss|dat}}} | {{{1|p|mpos|poss|dat}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss|dat}}} | {{{2|p|mpos|poss|dat}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss|dat}}} | {{{3|p|mpos|poss|dat}}} |- ! colspan="3" class="outer" | ခၞံဗဒှ်ဌာန်မတန်တဴ |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဨကဝုစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss|loc}}} | {{{1|s|mpos|poss|loc}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss|loc}}} | {{{2|s|mpos|poss|loc}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss|loc}}} | {{{3|s|mpos|poss|loc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss|loc}}} | {{{1|p|mpos|poss|loc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss|loc}}} | {{{2|p|mpos|poss|loc}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss|loc}}} | {{{3|p|mpos|poss|loc}}} |- ! colspan="3" class="outer" | ပရေၚ်မလၚ် |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss|abl}}} | {{{1|s|mpos|poss|abl}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss|abl}}} | {{{2|s|mpos|poss|abl}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss|abl}}} | {{{3|s|mpos|poss|abl}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss|abl}}} | {{{1|p|mpos|poss|abl}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss|abl}}} | {{{2|p|mpos|poss|abl}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss|abl}}} | {{{3|p|mpos|poss|abl}}} |- ! colspan="3" class="outer" | ဗဳဇဂကူ |- ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|spos|poss|gen}}} | {{{1|s|mpos|poss|gen}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|spos|poss|gen}}} | {{{2|s|mpos|poss|gen}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|spos|poss|gen}}} | {{{3|s|mpos|poss|gen}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|spos|poss|gen}}} | {{{1|p|mpos|poss|gen}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|spos|poss|gen}}} | {{{2|p|mpos|poss|gen}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|spos|poss|gen}}} | {{{3|p|mpos|poss|gen}}} ]=]) table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-bottom" }) end -- Predicative forms if data.has_pred then table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-top", args = { title = "Predicative forms", palette = "red", tall = "yes", } }) table.insert(wikicode, [=[ ! ! ကိုန်ဨကဝုစ် ! ကိုန်ဗဟုဝစ် |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၁ | {{{1|s|pred|of the|s}}} | {{{1|s|pred|of the|p}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၂ | {{{2|s|pred|of the|s}}} | {{{2|s|pred|of the|p}}} |- ! ကိုန်ဨကဝုစ်မရနုက်ကဵု၃ | {{{3|s|pred|of the|s}}} | {{{3|s|pred|of the|p}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၁ | {{{1|p|pred|of the|s}}} | {{{1|p|pred|of the|p}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၂ | {{{2|p|pred|of the|s}}} | {{{2|p|pred|of the|p}}} |- ! ကိုန်ဗဟုဝစ်မရနုက်ကဵု၃ | {{{3|p|pred|of the|s}}} | {{{3|p|pred|of the|p}}} ]=]) table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-table-bottom" }) end if data.has_poss or data.has_pred then table.insert(wikicode, '\n') table.insert(wikicode, mw.getCurrentFrame():expandTemplate{ title = "inflection-box-bottom" }) end return mw.ustring.gsub(table.concat(wikicode), "{{{([#!]?[a-z0-9| ]+)}}}", repl) .. require("Module:utilities").format_categories(data.categories, lang) end return export fys72vxrn5fobgrg93fzat479x3wjc2 မဝ်ဂျူ:tr-nouns/doc 828 295626 396281 2026-06-04T04:49:07Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|tr}} </includeonly>" 396281 wikitext text/x-wiki {{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|tr}} </includeonly> c2u8pxbmqcevbh7bjkapwaidiz4gxh0 ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲတူရကဳဂမၠိုၚ် 14 295627 396282 2026-06-04T04:50:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]]" 396282 wikitext text/x-wiki [[ကဏ္ဍ:မဝ်ဂျူတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]] 8ombad29ve8zm7web0lh8fo86fkwa0d ထာမ်ပလိက်:tr-infl-noun-c/documentation 10 295628 396283 2026-06-04T04:52:19Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} For listing the inflected forms of Turkish nouns ending in consonants. ==Required parameters== * 1= dominant vowel. (last vowel in the word) <!-- * 2= t/d (first letter of locative and ablative suffixes. t for words that end in unvoiced consonants, d for words that end in voiced consonants) --> ==Other parameters== If the last consonant in the word changes before the ending (as in {{l|tr|k..." 396283 wikitext text/x-wiki {{documentation subpage}} For listing the inflected forms of Turkish nouns ending in consonants. ==Required parameters== * 1= dominant vowel. (last vowel in the word) <!-- * 2= t/d (first letter of locative and ablative suffixes. t for words that end in unvoiced consonants, d for words that end in voiced consonants) --> ==Other parameters== If the last consonant in the word changes before the ending (as in {{l|tr|köpeği}} for {{l|tr|köpek}}): * stem= irregular stem in definite accusative, dative and definite possessive cases. For uncountable (singular-only) nouns, use {{para|n|s}}; for plural-only nouns (pluralia tantum), use {{para|n|p}}. To turn on the display of possessive-suffixed forms, use the parameter: * poss=1 And for turning on predicative forms, add * pred=1 ==See also== * [[:Template:tr-infl-noun-v]] – for Turkish nouns that end in a vowel * [[:Template:tr-noun-comp-v]] – for Turkish compound nouns, in which the second noun assumes the possessive form <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်တူရကဳဂမၠိုၚ်|c]] </includeonly> hnjy6dcoivgtwjkv2tf4ifd0yhluaxp ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်တူရကဳဂမၠိုၚ် 14 295629 396284 2026-06-04T04:53:34Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]]" 396284 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏတူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]] qapgly7rat5z06y0v3b51o7ne4ss5q2 ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏတူရကဳဂမၠိုၚ် 14 295630 396285 2026-06-04T04:55:06Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်တူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]]" 396285 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်တူရကဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|တ]] p37n2gjiy2p672myi04h4k2u1oaboim ထာမ်ပလိက်:inflection-table-bottom 10 295631 396288 2026-06-04T04:59:04Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:inflection-table-bottom]] ဇရေင် [[ထာမ်ပလိက်:inflection-box-bottom]] 396288 wikitext text/x-wiki #REDIRECT [[ထာမ်ပလိက်:inflection-box-bottom]] 8a8ynhc4v4yp68btfvxija6eeitoz2p ထာမ်ပလိက်:inflection-table-bottom/documentation 10 295632 396290 2026-06-04T04:59:05Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ထာမ်ပလိက်:inflection-table-bottom/documentation]] ဇရေင် [[ထာမ်ပလိက်:inflection-box-bottom/documentation]] 396290 wikitext text/x-wiki #REDIRECT [[ထာမ်ပလိက်:inflection-box-bottom/documentation]] 21cqban4t2woc9a3u6l1ukka4zoie6j ကဏ္ဍ:ဝေါဟာမလေဝ်ကၠုၚ်နူဝေါဟာဂရေတ်တြေံဂမၠိုၚ် 14 295633 396292 2026-06-04T05:03:01Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာမလေဝ်]]" 396292 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာမလေဝ်]] rmignogk0guq1n7q3c663ou42py1w0p ကဏ္ဍ:ကာရန်:သွဳဒေန်/iːk 14 295634 396293 2026-06-04T09:54:54Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသွဳဒေန်|သွဳဒေန်]] » :ကဏ္ဍ:ကာ..." 396293 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသွဳဒေန်|သွဳဒေန်]] » [[:ကဏ္ဍ:ကာရန်:သွဳဒေန်|ကာရန်ဂမၠိုၚ်]] » -iːk :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာသွဳဒေန်|သွဳဒေန်]]မနွံကာရန် [[ကာရန်:သွဳဒေန်/iːk|-iːk]] ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:သွဳဒေန်|iːk]] lp5y9ikxxhzg2mob3mynhqcmfehounn ကာရန်:သွဳဒေန်/iːk 106 295635 396294 2026-06-04T09:57:53Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|sv|iː|k}} ==ဗွဟ်ရမ္သာၚ်== /-iːk/, /-i:k/ ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== * [[fik]] * [[freak]] * [[geek]] * [[w:en:Kik|Kik]] (an app) * [[lik]] * [[pik]] * [[rik]] * [[sik]] * [[skrik]] * [[spik]] * [[tik]] * [[vik]] ===ဝဏ္ဏၜါ=== * [[antik]] * [[batik]] * [[butik]] * [[epik]] * [[etik]] * [[fabrik]] * [[fysik]] * [[gotik]] * gr..." 396294 wikitext text/x-wiki {{rhymes nav|sv|iː|k}} ==ဗွဟ်ရမ္သာၚ်== /-iːk/, /-i:k/ ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== * [[fik]] * [[freak]] * [[geek]] * [[w:en:Kik|Kik]] (an app) * [[lik]] * [[pik]] * [[rik]] * [[sik]] * [[skrik]] * [[spik]] * [[tik]] * [[vik]] ===ဝဏ္ဏၜါ=== * [[antik]] * [[batik]] * [[butik]] * [[epik]] * [[etik]] * [[fabrik]] * [[fysik]] * [[gotik]] * [[grafik]] * [[klinik]] * [[komik]] * [[kritik]] * [[kubik]] * [[logik]] * [[lyrik]] * [[mimik]] * [[musik]] * [[mystik]] * [[optik]] * [[panik]] * [[plastik]] * [[praktik]] * [[publik]] * [[relik]] * [[replik]] * [[rubrik]] * [[rustik]] * [[rytmik]] * [[rävtik]] * [[taktik]] * [[teknik]] * [[termik]] * [[trafik]] * [[tragik]] * [[unik]] ===ဝဏ္ဏပိ=== * [[akustik]] * [[arsenik]] * [[ballistik]] * [[botanik]] * [[didaktik]] * [[domestik]] * [[dramatik]] * [[dynamik]] * [[erotik]] * [[estetik]] * [[fantastik]] * [[fonetik]] * [[genetik]] * [[grammatik]] * [[gymnastik]] * [[Hallstavik]] * [[heraldik]] * [[historik]] * [[hydraulik]] * [[juridik]] * [[katolik]] * [[keramik]] * [[kosmetik]] * [[lingvistik]] * [[logistik]] * [[magnifik]] * [[mekanik]] * [[metodik]] * [[mosaik]] * [[motorik]] * [[patetik]] * [[poetik]] * [[polemik]] * [[politik]] * [[republik]] * [[retorik]] * [[romantik]] * [[semantik]] * [[specifik]] * [[statistik]] * [[stilistik]] * [[symbolik]] * [[tematik]] * [[Örnsköldsvik]] ===ဝဏ္ဏပန်=== * [[akrobatik]] * [[aritmetik]] * [[automatik]] * [[dialektik]] * [[elektronik]] * [[exegetik]] * [[geriatrik]] * [[informatik]] * [[journalistik]] * [[kalabalik]] * [[matematik]] * [[pedagogik]] * [[problematik]] * [[semiotik]] * [[systematik]] ===ဝဏ္ဏမသုန်=== * [[bananrepublik]] * [[karakteristik]] * [[karaktäristik]] * [[kvasiheraldik]] * [[pseudoheraldik]] 0atrrwc2qitab3okqjt43r4mu67etup ကာရန်:သွဳဒေန်/iː- 106 295636 396295 2026-06-04T09:59:55Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|sv|iː}} *[[Rhymes:သွဳဒေန်/iː|-iː]] *[[Rhymes:သွဳဒေန်/iːd|-iːd]] *[[Rhymes:သွဳဒေန်/iːg|-iːg]] *[[Rhymes:သွဳဒေန်/iːk|-iːk]] *[[Rhymes:သွဳဒေန်/iːl|-iːl]] *[[Rhymes:သွဳဒေန်/iːm|-iːm]] *[[Rhymes:သွဳဒေန်/iːn|-iːn]] *[[Rhymes:သွဳဒေန်/iːp|-iːp]] *Rhymes:သွဳဒေန်/iːr|-i..." 396295 wikitext text/x-wiki {{rhymes nav|sv|iː}} *[[Rhymes:သွဳဒေန်/iː|-iː]] *[[Rhymes:သွဳဒေန်/iːd|-iːd]] *[[Rhymes:သွဳဒေန်/iːg|-iːg]] *[[Rhymes:သွဳဒေန်/iːk|-iːk]] *[[Rhymes:သွဳဒေန်/iːl|-iːl]] *[[Rhymes:သွဳဒေန်/iːm|-iːm]] *[[Rhymes:သွဳဒေန်/iːn|-iːn]] *[[Rhymes:သွဳဒေန်/iːp|-iːp]] *[[Rhymes:သွဳဒေန်/iːr|-iːr]] *[[Rhymes:သွဳဒေန်/iːs|-iːs]] *[[Rhymes:သွဳဒေန်/iːt|-iːt]] *[[Rhymes:သွဳဒေန်/iːv|-iːv]] 62yxoch0cncglxrnwmk4oajrz2tjjp7 ကဏ္ဍ:ကာရန်သွဳဒေန်ဂမၠိုၚ်/iː- 14 295637 396296 2026-06-04T10:00:46Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ကာရန်သွဳဒေန်ဂမၠိုၚ်|iː-]]" 396296 wikitext text/x-wiki [[ကဏ္ဍ:ကာရန်သွဳဒေန်ဂမၠိုၚ်|iː-]] czte2loc3efyo01a3un8g4u0zggg8y4 ကဏ္ဍ:ကာရန်:သလဝ်ဝေန်နဳယျာ/atik 14 295638 396297 2026-06-04T10:03:02Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသလဝ်ဝေန်နဳယျာ|သလဝ်ဝေန်နဳ..." 396297 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဝ်ဝေန်နဳယျာ|သလဝ်ဝေန်နဳယျာ]] » [[:ကဏ္ဍ:ကာရန်:သလဝ်ဝေန်နဳယျာ|ကာရန်ဂမၠိုၚ်]] » -atik :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာသလဝ်ဝေန်နဳယျာ|သလဝ်ဝေန်နဳယျာ]]မနွံကာရန် atik ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:သလဝ်ဝေန်နဳယျာ|atik]] b8gnfq6lvw58o6kwph98rjoizzr3i0k ကဏ္ဍ:ကာရန်:သလဝ်ဝေန်နဳယျာ 14 295639 396298 2026-06-04T10:04:35Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာသလဝ်ဝေန်နဳယျာ]][[ကဏ္ဍ:ကာရန်ဂမၠိုၚ်|သ]]" 396298 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာသလဝ်ဝေန်နဳယျာ]][[ကဏ္ဍ:ကာရန်ဂမၠိုၚ်|သ]] dc1snxmn7plpb6qrw8sym5kvwc0qykl ကဏ္ဍ:ကာရန်:မလေဝ်/ɛtik 14 295640 396299 2026-06-04T10:07:06Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]] » :ကဏ္ဍ:ကာရန်:..." 396299 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]] » [[:ကဏ္ဍ:ကာရန်:မလေဝ်|ကာရန်ဂမၠိုၚ်]] » -ɛtik :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]]မနွံကာရန် ɛtik ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:မလေဝ်|ɛtik]] kg745bh0c4l6nk3xwffdoi2tkmh9el6 ကဏ္ဍ:ကာရန်:မလေဝ်/atik 14 295641 396300 2026-06-04T10:08:13Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]] » :ကဏ္ဍ:ကာရန်:..." 396300 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]] » [[:ကဏ္ဍ:ကာရန်:မလေဝ်|ကာရန်ဂမၠိုၚ်]] » -atik :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာမလေဝ်|မလေဝ်]]မနွံကာရန် atik ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:မလေဝ်|atik]] bfhlz2ybej2pwkxuhnhfbzdxltgvkxo ကဏ္ဍ:ကာရန်:ချက်ခ်/atɪk 14 295642 396301 2026-06-04T10:10:32Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာချက်ခ်|ချက်ခ်]] » :ကဏ္ဍ:ကာရန..." 396301 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာချက်ခ်|ချက်ခ်]] » [[:ကဏ္ဍ:ကာရန်:ချက်ခ်|ကာရန်ဂမၠိုၚ်]] » -atɪk :စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာချက်ခ်|ချက်ခ်]]မနွံကာရန် [[ကာရန်:ချက်ခ်/atɪk|-atɪk]] ဂမၠိုၚ်။ [[ကဏ္ဍ:ကာရန်:ချက်ခ်|atɪk]] gtup4rf8xwbvi8umoo7ecas6bti3uj5 ကာရန်:ချက်ခ်/atɪk 106 295643 396302 2026-06-04T10:13:51Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|cs|atɪk}} ==ဗွဟ်ရမ္သာၚ်== {{IPA|cs|/-atɪk/}} ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * [[statik]] {{rhyme-bottom}} ===ဝဏ္ဏၜါ=== {{rhyme-top}} * [[apatyk]] * [[dogmatik]] * [[dramatik]] * [[fanatik]] * [[flegmatik]] * [[gramatik]] * [[pragmatik]] {{rhyme-bottom}} ===ဝဏ္ဏပိ=== {{rhyme-top}} * [[automatik]] * av..." 396302 wikitext text/x-wiki {{rhymes nav|cs|atɪk}} ==ဗွဟ်ရမ္သာၚ်== {{IPA|cs|/-atɪk/}} ==ကာရန်ဂမၠိုၚ်== ===ဝဏ္ဏမွဲ=== {{rhyme-top}} * [[statik]] {{rhyme-bottom}} ===ဝဏ္ဏၜါ=== {{rhyme-top}} * [[apatyk]] * [[dogmatik]] * [[dramatik]] * [[fanatik]] * [[flegmatik]] * [[gramatik]] * [[pragmatik]] {{rhyme-bottom}} ===ဝဏ္ဏပိ=== {{rhyme-top}} * [[automatik]] * [[aviatik]] * [[informatik]] * [[matematik]] * [[pneumatik]] {{rhyme-bottom}} ===ဝဏ္ဏပန်=== {{rhyme-top}} * [[homeopatik]] {{rhyme-bottom}} 3qi5tcavz8mg8707ukiy7rfdgeb0qjb ကဏ္ဍ:ဝေါဟာခရိုၚ်မာၚ်တတာလွဳလဝ် နူဝေါဟာပြၚ်သေတ်ဂမၠိုၚ် 14 295644 396303 2026-06-04T10:15:11Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာခရိုၚ်မာၚ်တတာ]]" 396303 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာခရိုၚ်မာၚ်တတာ]] osqp21fledyf6ls19etd9e3ebtc2htg matematike 0 295645 396304 2026-06-04T10:18:33Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|matematikë|matemātiķē|matemātiķe}} ==အေက်သပရေန်တဝ်== ===ဗွဟ်ရမ္သာၚ်=== {{eo-pr|a=LL-Q143 (epo)-Lepticed7-matematike.wav}} ===ကြိယာဝိသေသန=== {{eo-head}} # အနေကနဲကဲသၚ်္ချာ။" 396304 wikitext text/x-wiki {{also|matematikë|matemātiķē|matemātiķe}} ==အေက်သပရေန်တဝ်== ===ဗွဟ်ရမ္သာၚ်=== {{eo-pr|a=LL-Q143 (epo)-Lepticed7-matematike.wav}} ===ကြိယာဝိသေသန=== {{eo-head}} # အနေကနဲကဲသၚ်္ချာ။ i9phtv8asdk5qs07fkc1t36gwpe2bue