ဝိက်ရှေန်နရဳ
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, " ", " ") .. '</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] = "—" -- Set missing forms to —
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] = "—" -- 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 "—", create the full link
if link ~= "" and link and link ~= "—" 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] = "—"
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}} [[{{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}} [[{{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 "—"
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