ဝိက်ရှေန်နရဳ
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.12
case-sensitive
မဳဒဳယာ
တၟေင်
ဓရီုကျာ
ညးလွပ်
ညးလွပ် ဓရီုကျာ
ဝိက်ရှေန်နရဳ
ဝိက်ရှေန်နရဳ ဓရီုကျာ
ဝှာင်
ဝှာင် ဓရီုကျာ
မဳဒဳယာဝဳကဳ
မဳဒဳယာဝဳကဳ ဓရီုကျာ
ထာမ်ပလိက်
ထာမ်ပလိက် ဓရီုကျာ
ရီု
ရီု ဓရီုကျာ
ကဏ္ဍ
ကဏ္ဍ ဓရီုကျာ
အဆက်လက္ကရဴ
အဆက်လက္ကရဴ ဓရီုကျာ
ကာရန်
ကာရန် ဓရီုကျာ
အဘိဓာန်
အဘိဓာန် ဓရီုကျာ
ဗီုပြၚ်သိုၚ်တၟိ
ဗီုပြၚ်သိုၚ်တၟိ ဓရီုကျာ
TimedText
TimedText talk
မဝ်ဂျူ
မဝ်ဂျူ ဓရီုကျာ
Event
Event talk
မဝ်ဂျူ:scripts/data
828
676
399770
392936
2026-07-20T15:11:45Z
咽頭べさ
33
399770
Scribunto
text/plain
--[=[
When adding new scripts to this file, please don't forget to add
style definitons for the script in [[MediaWiki:Gadget-LanguagesAndScripts.css]].
]=]
local concat = table.concat
local insert = table.insert
local ipairs = ipairs
local next = next
local remove = table.remove
local select = select
local sort = table.sort
-- Loaded on demand, as it may not be needed (depending on the data).
local function u(...)
u = require("Module:string utilities").char
return u(...)
end
------------------------------------------------------------------------------------
--
-- Helper functions
--
------------------------------------------------------------------------------------
-- Note: a[2] > b[2] means opens are sorted before closes if otherwise equal.
local function sort_ranges(a, b)
return a[1] < b[1] or a[1] == b[1] and a[2] > b[2]
end
-- Returns the union of two or more range tables.
local function union(...)
local ranges = {}
for i = 1, select("#", ...) do
local argt = select(i, ...)
for j, v in ipairs(argt) do
insert(ranges, {v, j % 2 == 1 and 1 or -1})
end
end
sort(ranges, sort_ranges)
local ret, i = {}, 0
for _, range in ipairs(ranges) do
i = i + range[2]
if i == 0 and range[2] == -1 then -- close
insert(ret, range[1])
elseif i == 1 and range[2] == 1 then -- open
if ret[#ret] and range[1] <= ret[#ret] + 1 then
remove(ret) -- merge adjacent ranges
else
insert(ret, range[1])
end
end
end
return ret
end
-- Adds the `characters` key, which is determined by a script's `ranges` table.
local function process_ranges(sc)
local ranges, chars = sc.ranges, {}
for i = 2, #ranges, 2 do
if ranges[i] == ranges[i - 1] then
insert(chars, u(ranges[i]))
else
insert(chars, u(ranges[i - 1]))
if ranges[i] > ranges[i - 1] + 1 then
insert(chars, "-")
end
insert(chars, u(ranges[i]))
end
end
sc.characters = concat(chars)
ranges.n = #ranges
return sc
end
local function handle_normalization_fixes(fixes)
local combiningClasses = fixes.combiningClasses
if combiningClasses then
local chars, i = {}, 0
for char in next, combiningClasses do
i = i + 1
chars[i] = char
end
fixes.combiningClassCharacters = concat(chars)
end
return fixes
end
------------------------------------------------------------------------------------
--
-- Data
--
------------------------------------------------------------------------------------
local m = {}
m["Adlm"] = process_ranges{
"အာက်လာမ်",
19606346,
"alphabet",
ranges = {
0x061F, 0x061F,
0x0640, 0x0640,
0x1E900, 0x1E94B,
0x1E950, 0x1E959,
0x1E95E, 0x1E95F,
},
capitalized = true,
direction = "rtl",
}
m["Afak"] = {
"Afaka",
382019,
"syllabary",
-- Not in Unicode
}
m["Aghb"] = process_ranges{
"ခါခေယှေန် အာယ်လ်ဘေနဳယာန်",
2495716,
"alphabet",
ranges = {
0x10530, 0x10563,
0x1056F, 0x1056F,
},
}
m["Ahom"] = process_ranges{
"အာဟုမ်",
2839633,
"abugida",
ranges = {
0x11700, 0x1171A,
0x1171D, 0x1172B,
0x11730, 0x11746,
},
}
m["Arab"] = process_ranges{
"အာရဗဳ",
1828555,
"abjad", -- more precisely, impure abjad
varieties = {"Jawi", {"Nastaliq", "Nastaleeq"}},
ranges = {
0x0600, 0x06FF,
0x0750, 0x077F,
0x0870, 0x088E,
0x0890, 0x0891,
0x0897, 0x08E1,
0x08E3, 0x08FF,
0xFB50, 0xFBC2,
0xFBD3, 0xFD8F,
0xFD92, 0xFDC7,
0xFDCF, 0xFDCF,
0xFDF0, 0xFDFF,
0xFE70, 0xFE74,
0xFE76, 0xFEFC,
0x102E0, 0x102FB,
0x10E60, 0x10E7E,
0x10EC2, 0x10EC4,
0x10EFC, 0x10EFF,
0x1EE00, 0x1EE03,
0x1EE05, 0x1EE1F,
0x1EE21, 0x1EE22,
0x1EE24, 0x1EE24,
0x1EE27, 0x1EE27,
0x1EE29, 0x1EE32,
0x1EE34, 0x1EE37,
0x1EE39, 0x1EE39,
0x1EE3B, 0x1EE3B,
0x1EE42, 0x1EE42,
0x1EE47, 0x1EE47,
0x1EE49, 0x1EE49,
0x1EE4B, 0x1EE4B,
0x1EE4D, 0x1EE4F,
0x1EE51, 0x1EE52,
0x1EE54, 0x1EE54,
0x1EE57, 0x1EE57,
0x1EE59, 0x1EE59,
0x1EE5B, 0x1EE5B,
0x1EE5D, 0x1EE5D,
0x1EE5F, 0x1EE5F,
0x1EE61, 0x1EE62,
0x1EE64, 0x1EE64,
0x1EE67, 0x1EE6A,
0x1EE6C, 0x1EE72,
0x1EE74, 0x1EE77,
0x1EE79, 0x1EE7C,
0x1EE7E, 0x1EE7E,
0x1EE80, 0x1EE89,
0x1EE8B, 0x1EE9B,
0x1EEA1, 0x1EEA3,
0x1EEA5, 0x1EEA9,
0x1EEAB, 0x1EEBB,
0x1EEF0, 0x1EEF1,
},
direction = "rtl",
normalizationFixes = handle_normalization_fixes{
from = {"ٳ"},
to = {"اٟ"}
},
}
m["fa-Arab"] = {
"အာရဗဳ",
744068,
m["Arab"][3],
ranges = m["Arab"].ranges,
characters = m["Arab"].characters,
otherNames = {"Perso-Arabic"},
direction = "rtl",
parent = "Arab",
normalizationFixes = m["Arab"].normalizationFixes,
}
m["kk-Arab"] = {
"အာရဗဳ",
90681452,
m["Arab"][3],
ranges = m["Arab"].ranges,
characters = m["Arab"].characters,
direction = "rtl",
parent = "Arab",
normalizationFixes = m["Arab"].normalizationFixes,
}
m["ks-Arab"] = m["fa-Arab"]
m["ku-Arab"] = m["fa-Arab"]
m["ms-Arab"] = m["kk-Arab"]
m["mzn-Arab"] = m["fa-Arab"]
m["ota-Arab"] = m["fa-Arab"]
m["pa-Arab"] = {
"ချာမူခဳ",
133800,
m["Arab"][3],
ranges = m["Arab"].ranges,
characters = m["Arab"].characters,
otherNames = {"Arabic"},
direction = "rtl",
parent = "Arab",
normalizationFixes = m["Arab"].normalizationFixes,
}
m["ps-Arab"] = m["fa-Arab"]
m["sd-Arab"] = m["fa-Arab"]
m["tt-Arab"] = m["fa-Arab"]
m["ug-Arab"] = m["fa-Arab"]
m["ur-Arab"] = m["fa-Arab"]
-- Aran (Nastaliq) is subsumed into Arab
m["Armi"] = process_ranges{
"အၚ်ဖဳရေဲ အာရမေအဳ",
26978,
"abjad",
ranges = {
0x10840, 0x10855,
0x10857, 0x1085F,
},
direction = "rtl",
}
m["Armn"] = process_ranges{
"အာမေနဳယျာ",
11932,
"alphabet",
ranges = {
0x0531, 0x0556,
0x0559, 0x058A,
0x058D, 0x058F,
0xFB13, 0xFB17,
},
capitalized = true,
}
m["Avst"] = process_ranges{
"အဗါတ်သတေန်",
790681,
"alphabet",
ranges = {
0x10B00, 0x10B35,
0x10B39, 0x10B3F,
},
direction = "rtl",
}
m["pal-Avst"] = {
"Pazend",
4925073,
m["Avst"][3],
ranges = m["Avst"].ranges,
characters = m["Avst"].characters,
direction = "rtl",
parent = "Avst",
}
m["Bali"] = process_ranges{
"ပဲါလဳ",
804984,
"abugida",
ranges = {
0x1B00, 0x1B4C,
0x1B4E, 0x1B7F,
},
}
m["Bamu"] = process_ranges{
"Bamum",
806024,
"syllabary",
ranges = {
0xA6A0, 0xA6F7,
0x16800, 0x16A38,
},
}
m["Bass"] = process_ranges{
"Bassa",
810458,
"alphabet",
aliases = {"Bassa Vah", "Vah"},
ranges = {
0x16AD0, 0x16AED,
0x16AF0, 0x16AF5,
},
}
m["Batk"] = process_ranges{
"Batak",
51592,
"abugida",
ranges = {
0x1BC0, 0x1BF3,
0x1BFC, 0x1BFF,
},
}
m["Beng"] = process_ranges{
"ဘၚ်္ဂါလဳ",
756802,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0980, 0x0983,
0x0985, 0x098C,
0x098F, 0x0990,
0x0993, 0x09A8,
0x09AA, 0x09B0,
0x09B2, 0x09B2,
0x09B6, 0x09B9,
0x09BC, 0x09C4,
0x09C7, 0x09C8,
0x09CB, 0x09CE,
0x09D7, 0x09D7,
0x09DC, 0x09DD,
0x09DF, 0x09E3,
0x09E6, 0x09EF,
0x09F2, 0x09FE,
0x1CD0, 0x1CD0,
0x1CD2, 0x1CD2,
0x1CD5, 0x1CD6,
0x1CD8, 0x1CD8,
0x1CE1, 0x1CE1,
0x1CEA, 0x1CEA,
0x1CED, 0x1CED,
0x1CF2, 0x1CF2,
0x1CF5, 0x1CF7,
0xA8F1, 0xA8F1,
},
normalizationFixes = handle_normalization_fixes{
from = {"অা", "ঋৃ", "ঌৢ"},
to = {"আ", "ৠ", "ৡ"}
},
}
m["as-Beng"] = process_ranges{
"အေက်စမဳ",
191272,
m["Beng"][3],
otherNames = {"Eastern Nagari"},
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0980, 0x0983,
0x0985, 0x098C,
0x098F, 0x0990,
0x0993, 0x09A8,
0x09AA, 0x09AF,
0x09B2, 0x09B2,
0x09B6, 0x09B9,
0x09BC, 0x09C4,
0x09C7, 0x09C8,
0x09CB, 0x09CE,
0x09D7, 0x09D7,
0x09DC, 0x09DD,
0x09DF, 0x09E3,
0x09E6, 0x09FE,
0x1CD0, 0x1CD0,
0x1CD2, 0x1CD2,
0x1CD5, 0x1CD6,
0x1CD8, 0x1CD8,
0x1CE1, 0x1CE1,
0x1CEA, 0x1CEA,
0x1CED, 0x1CED,
0x1CF2, 0x1CF2,
0x1CF5, 0x1CF7,
0xA8F1, 0xA8F1,
},
normalizationFixes = m["Beng"].normalizationFixes,
}
m["Bhks"] = process_ranges{
"လေတ်ရှုကဳ",
17017839,
"abugida",
ranges = {
0x11C00, 0x11C08,
0x11C0A, 0x11C36,
0x11C38, 0x11C45,
0x11C50, 0x11C6C,
},
}
m["Blis"] = {
"Blissymbolic",
609817,
"logography",
aliases = {"Blissymbols"},
-- Not in Unicode
}
m["Bopo"] = process_ranges{
"စူယေၚ်",
198269,
"semisyllabary",
aliases = {"Zhuyin Fuhao", "Bopomofo"},
ranges = {
0x02EA, 0x02EB,
0x3001, 0x3003,
0x3008, 0x3011,
0x3013, 0x301F,
0x302A, 0x302D,
0x3030, 0x3030,
0x3037, 0x3037,
0x30FB, 0x30FB,
0x3105, 0x312F,
0x31A0, 0x31BF,
0xFE45, 0xFE46,
0xFF61, 0xFF65,
},
}
m["Brah"] = process_ranges{
"ဖရာမ်မဳလ်",
185083,
"abugida",
ranges = {
0x11000, 0x1104D,
0x11052, 0x11075,
0x1107F, 0x1107F,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑀅𑀸", "𑀋𑀾", "𑀏𑁂"},
to = {"𑀆", "𑀌", "𑀐"}
},
}
m["Brai"] = process_ranges{
"လိက်မတ်ပၠတ်",
79894,
"alphabet",
ranges = {
0x2800, 0x28FF,
},
}
m["Bugi"] = process_ranges{
"Lontara",
1074947,
"abugida",
aliases = {"Buginese"},
ranges = {
0x1A00, 0x1A1B,
0x1A1E, 0x1A1F,
0xA9CF, 0xA9CF,
},
}
m["Buhd"] = process_ranges{
"Buhid",
1002969,
"abugida",
ranges = {
0x1735, 0x1736,
0x1740, 0x1751,
0x1752, 0x1753,
},
}
m["Cakm"] = process_ranges{
"ချေန်ကမာ",
1059328,
"abugida",
ranges = {
0x09E6, 0x09EF,
0x1040, 0x1049,
0x11100, 0x11134,
0x11136, 0x11147,
},
}
m["Cans"] = process_ranges{
"Canadian syllabic",
2479183,
"abugida",
ranges = {
0x1400, 0x167F,
0x18B0, 0x18F5,
0x11AB0, 0x11ABF,
},
}
m["Cari"] = process_ranges{
"Carian",
1094567,
"alphabet",
ranges = {
0x102A0, 0x102D0,
},
}
m["Cham"] = process_ranges{
"Cham",
1060381,
"abugida",
ranges = {
0xAA00, 0xAA36,
0xAA40, 0xAA4D,
0xAA50, 0xAA59,
0xAA5C, 0xAA5F,
},
}
m["Cher"] = process_ranges{
"Cherokee",
26549,
"syllabary",
ranges = {
0x13A0, 0x13F5,
0x13F8, 0x13FD,
0xAB70, 0xABBF,
},
}
m["Chis"] = {
"Chisoi",
123173777,
"abugida",
-- Not in Unicode
}
m["Chrs"] = process_ranges{
"Khwarezmian",
72386710,
"abjad",
aliases = {"Chorasmian"},
ranges = {
0x10FB0, 0x10FCB,
},
direction = "rtl",
}
m["Copt"] = process_ranges{
"Coptic",
321083,
"alphabet",
ranges = {
0x03E2, 0x03EF,
0x2C80, 0x2CF3,
0x2CF9, 0x2CFF,
0x102E0, 0x102FB,
},
capitalized = true,
}
m["Cpmn"] = process_ranges{
"Cypro-Minoan",
1751985,
"syllabary",
aliases = {"Cypro Minoan"},
ranges = {
0x10100, 0x10101,
0x12F90, 0x12FF2,
},
}
m["Cprt"] = process_ranges{
"Cypriot",
1757689,
"syllabary",
ranges = {
0x10100, 0x10102,
0x10107, 0x10133,
0x10137, 0x1013F,
0x10800, 0x10805,
0x10808, 0x10808,
0x1080A, 0x10835,
0x10837, 0x10838,
0x1083C, 0x1083C,
0x1083F, 0x1083F,
},
direction = "rtl",
}
m["Cyrl"] = process_ranges{
"စဳရယ်လ်",
8209,
"alphabet",
ranges = {
0x0400, 0x052F,
0x1C80, 0x1C8A,
0x1D2B, 0x1D2B,
0x1D78, 0x1D78,
0x1DF8, 0x1DF8,
0x2DE0, 0x2DFF,
0x2E43, 0x2E43,
0xA640, 0xA69F,
0xFE2E, 0xFE2F,
0x1E030, 0x1E06D,
0x1E08F, 0x1E08F,
},
capitalized = true,
}
m["Cyrs"] = {
"စဳရယ်လ်တြေံ",
442244,
m["Cyrl"][3],
aliases = {"Early Cyrillic"},
ranges = m["Cyrl"].ranges,
characters = m["Cyrl"].characters,
capitalized = m["Cyrl"].capitalized,
wikipedia_article = "Early Cyrillic alphabet",
normalizationFixes = handle_normalization_fixes{
from = {"Ѹ", "ѹ"},
to = {"Ꙋ", "ꙋ"}
},
}
m["Deva"] = process_ranges{
"ထေဝနာခရေဝ်",
38592,
"abugida",
ranges = {
0x0900, 0x097F,
0x1CD0, 0x1CF6,
0x1CF8, 0x1CF9,
0x20F0, 0x20F0,
0xA830, 0xA839,
0xA8E0, 0xA8FF,
0x11B00, 0x11B09,
},
normalizationFixes = handle_normalization_fixes{
from = {"ॆॆ", "ेे", "ाॅ", "ाॆ", "ाꣿ", "ॊॆ", "ाे", "ाै", "ोे", "ाऺ", "ॖॖ", "अॅ", "अॆ", "अा", "एॅ", "एॆ", "एे", "एꣿ", "ऎॆ", "अॉ", "आॅ", "अॊ", "आॆ", "अो", "आे", "अौ", "आै", "ओे", "अऺ", "अऻ", "आऺ", "अाꣿ", "आꣿ", "ऒॆ", "अॖ", "अॗ", "ॶॖ", "्?ा"},
to = {"ꣿ", "ै", "ॉ", "ॊ", "ॏ", "ॏ", "ो", "ौ", "ौ", "ऻ", "ॗ", "ॲ", "ऄ", "आ", "ऍ", "ऎ", "ऐ", "ꣾ", "ꣾ", "ऑ", "ऑ", "ऒ", "ऒ", "ओ", "ओ", "औ", "औ", "औ", "ॳ", "ॴ", "ॴ", "ॵ", "ॵ", "ॵ", "ॶ", "ॷ", "ॷ"}
},
}
m["Diak"] = process_ranges{
"Dhives Akuru",
3307073,
"abugida",
aliases = {"Dhivehi Akuru", "Dives Akuru", "Divehi Akuru"},
ranges = {
0x11900, 0x11906,
0x11909, 0x11909,
0x1190C, 0x11913,
0x11915, 0x11916,
0x11918, 0x11935,
0x11937, 0x11938,
0x1193B, 0x11946,
0x11950, 0x11959,
},
}
m["Dogr"] = process_ranges{
"Dogra",
72402987,
"abugida",
ranges = {
0x0964, 0x096F,
0xA830, 0xA839,
0x11800, 0x1183B,
},
}
m["Dsrt"] = process_ranges{
"Deseret",
1200582,
"alphabet",
ranges = {
0x10400, 0x1044F,
},
capitalized = true,
}
m["Dupl"] = process_ranges{
"Duployan",
5316025,
"alphabet",
ranges = {
0x1BC00, 0x1BC6A,
0x1BC70, 0x1BC7C,
0x1BC80, 0x1BC88,
0x1BC90, 0x1BC99,
0x1BC9C, 0x1BCA3,
},
}
m["Egyd"] = {
"Demotic",
188519,
"abjad, logography",
-- Not in Unicode
}
m["Egyh"] = {
"Hieratic",
208111,
"abjad, logography",
-- Unified with Egyptian hieroglyphic in Unicode
}
m["Egyp"] = process_ranges{
"Egyptian hieroglyphic",
132659,
"abjad, logography",
ranges = {
0x13000, 0x13455,
0x13460, 0x143FA,
},
varieties = {"Hieratic"},
wikipedia_article = "Egyptian hieroglyphs",
normalizationFixes = handle_normalization_fixes{
from = {"𓃁", "𓆖"},
to = {"𓃀𓂝", "𓆓𓏏𓇿"}
},
}
m["Elba"] = process_ranges{
"Elbasan",
1036714,
"alphabet",
ranges = {
0x10500, 0x10527,
},
}
m["Elym"] = process_ranges{
"Elymaic",
60744423,
"abjad",
ranges = {
0x10FE0, 0x10FF6,
},
direction = "rtl",
}
m["Ethi"] = process_ranges{
"Ethiopic",
257634,
"abugida",
aliases = {"Ge'ez", "Geʽez"},
ranges = {
0x1200, 0x1248,
0x124A, 0x124D,
0x1250, 0x1256,
0x1258, 0x1258,
0x125A, 0x125D,
0x1260, 0x1288,
0x128A, 0x128D,
0x1290, 0x12B0,
0x12B2, 0x12B5,
0x12B8, 0x12BE,
0x12C0, 0x12C0,
0x12C2, 0x12C5,
0x12C8, 0x12D6,
0x12D8, 0x1310,
0x1312, 0x1315,
0x1318, 0x135A,
0x135D, 0x137C,
0x1380, 0x1399,
0x2D80, 0x2D96,
0x2DA0, 0x2DA6,
0x2DA8, 0x2DAE,
0x2DB0, 0x2DB6,
0x2DB8, 0x2DBE,
0x2DC0, 0x2DC6,
0x2DC8, 0x2DCE,
0x2DD0, 0x2DD6,
0x2DD8, 0x2DDE,
0xAB01, 0xAB06,
0xAB09, 0xAB0E,
0xAB11, 0xAB16,
0xAB20, 0xAB26,
0xAB28, 0xAB2E,
0x1E7E0, 0x1E7E6,
0x1E7E8, 0x1E7EB,
0x1E7ED, 0x1E7EE,
0x1E7F0, 0x1E7FE,
},
}
m["Gara"] = process_ranges{
"Garay",
3095302,
"alphabet",
capitalized = true,
direction = "rtl",
ranges = {
0x060C, 0x060C,
0x061B, 0x061B,
0x061F, 0x061F,
0x10D40, 0x10D65,
0x10D69, 0x10D85,
0x10D8E, 0x10D8F,
},
}
m["Geok"] = process_ranges{
"Khutsuri",
1090055,
"alphabet",
ranges = { -- Ⴀ-Ⴭ is Asomtavruli, ⴀ-ⴭ is Nuskhuri
0x10A0, 0x10C5,
0x10C7, 0x10C7,
0x10CD, 0x10CD,
0x10FB, 0x10FB,
0x2D00, 0x2D25,
0x2D27, 0x2D27,
0x2D2D, 0x2D2D,
},
varieties = {"Nuskhuri", "Asomtavruli"},
capitalized = true,
}
m["Geor"] = process_ranges{
"Georgian",
3317411,
"alphabet",
ranges = { -- ა-ჿ is lowercase Mkhedruli; Ა-Ჿ is uppercase Mkhedruli (Mtavruli)
0x0589, 0x0589,
0x10D0, 0x10FF,
0x1C90, 0x1CBA,
0x1CBD, 0x1CBF,
},
varieties = {"Mkhedruli", "Mtavruli"},
capitalized = true,
}
m["Glag"] = process_ranges{
"Glagolitic",
145625,
"alphabet",
ranges = {
0x0484, 0x0484,
0x0487, 0x0487,
0x0589, 0x0589,
0x10FB, 0x10FB,
0x2C00, 0x2C5F,
0x2E43, 0x2E43,
0xA66F, 0xA66F,
0x1E000, 0x1E006,
0x1E008, 0x1E018,
0x1E01B, 0x1E021,
0x1E023, 0x1E024,
0x1E026, 0x1E02A,
},
capitalized = true,
}
m["Gong"] = process_ranges{
"Gunjala Gondi",
18125340,
"abugida",
ranges = {
0x0964, 0x0965,
0x11D60, 0x11D65,
0x11D67, 0x11D68,
0x11D6A, 0x11D8E,
0x11D90, 0x11D91,
0x11D93, 0x11D98,
0x11DA0, 0x11DA9,
},
}
m["Gonm"] = process_ranges{
"Masaram Gondi",
16977603,
"abugida",
ranges = {
0x0964, 0x0965,
0x11D00, 0x11D06,
0x11D08, 0x11D09,
0x11D0B, 0x11D36,
0x11D3A, 0x11D3A,
0x11D3C, 0x11D3D,
0x11D3F, 0x11D47,
0x11D50, 0x11D59,
},
}
m["Goth"] = process_ranges{
"Gothic",
467784,
"alphabet",
ranges = {
0x10330, 0x1034A,
},
wikipedia_article = "Gothic alphabet",
}
m["Gran"] = process_ranges{
"ဂရေန်တာ",
1119274,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0BE6, 0x0BF3,
0x1CD0, 0x1CD0,
0x1CD2, 0x1CD3,
0x1CF2, 0x1CF4,
0x1CF8, 0x1CF9,
0x20F0, 0x20F0,
0x11300, 0x11303,
0x11305, 0x1130C,
0x1130F, 0x11310,
0x11313, 0x11328,
0x1132A, 0x11330,
0x11332, 0x11333,
0x11335, 0x11339,
0x1133B, 0x11344,
0x11347, 0x11348,
0x1134B, 0x1134D,
0x11350, 0x11350,
0x11357, 0x11357,
0x1135D, 0x11363,
0x11366, 0x1136C,
0x11370, 0x11374,
0x11FD0, 0x11FD1,
0x11FD3, 0x11FD3,
},
}
m["Grek"] = process_ranges{
"ဂရေတ်",
8216,
"alphabet",
ranges = {
0x0342, 0x0342,
0x0345, 0x0345,
0x0370, 0x0377,
0x037A, 0x037F,
0x0384, 0x038A,
0x038C, 0x038C,
0x038E, 0x03A1,
0x03A3, 0x03E1,
0x03F0, 0x03FF,
0x1D26, 0x1D2A,
0x1D5D, 0x1D61,
0x1D66, 0x1D6A,
0x1DBF, 0x1DBF,
0x2126, 0x2127,
0x2129, 0x2129,
0x213C, 0x2140,
0xAB65, 0xAB65,
0x10140, 0x1018E,
0x101A0, 0x101A0,
0x1D200, 0x1D245,
},
capitalized = true,
}
m["Polyt"] = process_ranges{
"ဂရေတ်",
1475332,
m["Grek"][3],
ranges = union(m["Grek"].ranges, {
0x1F00, 0x1F15,
0x1F18, 0x1F1D,
0x1F20, 0x1F45,
0x1F48, 0x1F4D,
0x1F50, 0x1F57,
0x1F59, 0x1F59,
0x1F5B, 0x1F5B,
0x1F5D, 0x1F5D,
0x1F5F, 0x1F7D,
0x1F80, 0x1FB4,
0x1FB6, 0x1FC4,
0x1FC6, 0x1FD3,
0x1FD6, 0x1FDB,
0x1FDD, 0x1FEF,
0x1FF2, 0x1FF4,
0x1FF6, 0x1FFE,
}),
ietf_subtag = "Grek",
capitalized = m["Grek"].capitalized,
parent = "Grek",
}
m["Gujr"] = process_ranges{
"ဂုဂျာရတဳ",
733944,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0A81, 0x0A83,
0x0A85, 0x0A8D,
0x0A8F, 0x0A91,
0x0A93, 0x0AA8,
0x0AAA, 0x0AB0,
0x0AB2, 0x0AB3,
0x0AB5, 0x0AB9,
0x0ABC, 0x0AC5,
0x0AC7, 0x0AC9,
0x0ACB, 0x0ACD,
0x0AD0, 0x0AD0,
0x0AE0, 0x0AE3,
0x0AE6, 0x0AF1,
0x0AF9, 0x0AFF,
0xA830, 0xA839,
},
normalizationFixes = handle_normalization_fixes{
from = {"ઓ", "અાૈ", "અા", "અૅ", "અે", "અૈ", "અૉ", "અો", "અૌ", "આૅ", "આૈ", "ૅા"},
to = {"અાૅ", "ઔ", "આ", "ઍ", "એ", "ઐ", "ઑ", "ઓ", "ઔ", "ઓ", "ઔ", "ૉ"}
},
}
m["Gukh"] = process_ranges{
"Khema",
110064239,
"abugida",
aliases = {"Gurung Khema", "Khema Phri", "Khema Lipi"},
ranges = {
0x0965, 0x0965,
0x16100, 0x16139,
},
}
m["Guru"] = process_ranges{
"ဂူမူခဳ",
689894,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0A01, 0x0A03,
0x0A05, 0x0A0A,
0x0A0F, 0x0A10,
0x0A13, 0x0A28,
0x0A2A, 0x0A30,
0x0A32, 0x0A33,
0x0A35, 0x0A36,
0x0A38, 0x0A39,
0x0A3C, 0x0A3C,
0x0A3E, 0x0A42,
0x0A47, 0x0A48,
0x0A4B, 0x0A4D,
0x0A51, 0x0A51,
0x0A59, 0x0A5C,
0x0A5E, 0x0A5E,
0x0A66, 0x0A76,
0xA830, 0xA839,
},
normalizationFixes = handle_normalization_fixes{
from = {"ਅਾ", "ਅੈ", "ਅੌ", "ੲਿ", "ੲੀ", "ੲੇ", "ੳੁ", "ੳੂ", "ੳੋ"},
to = {"ਆ", "ਐ", "ਔ", "ਇ", "ਈ", "ਏ", "ਉ", "ਊ", "ਓ"}
},
}
m["Hang"] = process_ranges{
"ဟန်ဂူ",
8222,
"syllabary",
aliases = {"Hangeul"},
ranges = {
0x1100, 0x11FF,
0x3001, 0x3003,
0x3008, 0x3011,
0x3013, 0x301F,
0x302E, 0x3030,
0x3037, 0x3037,
0x30FB, 0x30FB,
0x3131, 0x318E,
0x3200, 0x321E,
0x3260, 0x327E,
0xA960, 0xA97C,
0xAC00, 0xD7A3,
0xD7B0, 0xD7C6,
0xD7CB, 0xD7FB,
0xFE45, 0xFE46,
0xFF61, 0xFF65,
0xFFA0, 0xFFBE,
0xFFC2, 0xFFC7,
0xFFCA, 0xFFCF,
0xFFD2, 0xFFD7,
0xFFDA, 0xFFDC,
},
}
m["Hani"] = process_ranges{
"ဟာန်",
8201,
"logography",
ranges = {
0x2E80, 0x2E99,
0x2E9B, 0x2EF3,
0x2F00, 0x2FD5,
0x2FF0, 0x2FFF,
0x3001, 0x3003,
0x3005, 0x3011,
0x3013, 0x301F,
0x3021, 0x302D,
0x3030, 0x3030,
0x3037, 0x303F,
0x3190, 0x319F,
0x31C0, 0x31E5,
0x31EF, 0x31EF,
0x3220, 0x3247,
0x3280, 0x32B0,
0x32C0, 0x32CB,
0x30FB, 0x30FB,
0x32FF, 0x32FF,
0x3358, 0x3370,
0x337B, 0x337F,
0x33E0, 0x33FE,
0x3400, 0x4DBF,
0x4E00, 0x9FFF,
0xA700, 0xA707,
0xF900, 0xFA6D,
0xFA70, 0xFAD9,
0xFE45, 0xFE46,
0xFF61, 0xFF65,
0x16FE2, 0x16FE3,
0x16FF0, 0x16FF1,
0x1D360, 0x1D371,
0x1F250, 0x1F251,
0x20000, 0x2A6DF,
0x2A700, 0x2B739,
0x2B740, 0x2B81D,
0x2B820, 0x2CEA1,
0x2CEB0, 0x2EBE0,
0x2EBF0, 0x2EE5D,
0x2F800, 0x2FA1D,
0x30000, 0x3134A,
0x31350, 0x323AF,
},
varieties = {"Hanzi", "Kanji", "Hanja", "Chu Nom"},
spaces = false,
}
m["Hans"] = {
"Simplified Han",
185614,
m["Hani"][3],
ranges = m["Hani"].ranges,
characters = m["Hani"].characters,
spaces = m["Hani"].spaces,
parent = "Hani",
}
m["Hant"] = {
"Traditional Han",
178528,
m["Hani"][3],
ranges = m["Hani"].ranges,
characters = m["Hani"].characters,
spaces = m["Hani"].spaces,
parent = "Hani",
}
m["Hano"] = process_ranges{
"ဟာန်နနူ",
1584045,
"abugida",
aliases = {"Hanunó'o", "Hanuno'o"},
ranges = {
0x1720, 0x1736,
},
}
m["Hatr"] = process_ranges{
"ဟေက်ထရာန်",
20813038,
"abjad",
ranges = {
0x108E0, 0x108F2,
0x108F4, 0x108F5,
0x108FB, 0x108FF,
},
direction = "rtl",
}
m["Hebr"] = process_ranges{
"ဟဳဘရဝ်",
33513,
"abjad", -- more precisely, impure abjad
ranges = {
0x0591, 0x05C7,
0x05D0, 0x05EA,
0x05EF, 0x05F4,
0x2135, 0x2138,
0xFB1D, 0xFB36,
0xFB38, 0xFB3C,
0xFB3E, 0xFB3E,
0xFB40, 0xFB41,
0xFB43, 0xFB44,
0xFB46, 0xFB4F,
},
direction = "rtl",
}
m["Hira"] = process_ranges{
"ဟဳရာဂါနာ",
48332,
"syllabary",
ranges = {
0x3001, 0x3003,
0x3008, 0x3011,
0x3013, 0x301F,
0x3030, 0x3035,
0x3037, 0x3037,
0x303C, 0x303D,
0x3041, 0x3096,
0x3099, 0x30A0,
0x30FB, 0x30FC,
0xFE45, 0xFE46,
0xFF61, 0xFF65,
0xFF70, 0xFF70,
0xFF9E, 0xFF9F,
0x1B001, 0x1B11F,
0x1B132, 0x1B132,
0x1B150, 0x1B152,
0x1F200, 0x1F200,
},
varieties = {"Hentaigana"},
spaces = false,
}
m["Hluw"] = process_ranges{
"Anatolian hieroglyphic",
521323,
"logography, syllabary",
ranges = {
0x14400, 0x14646,
},
wikipedia_article = "Anatolian hieroglyphs",
}
m["Hmng"] = process_ranges{
"ပါဝမောန်",
365954,
"semisyllabary",
aliases = {"Hmong"},
ranges = {
0x16B00, 0x16B45,
0x16B50, 0x16B59,
0x16B5B, 0x16B61,
0x16B63, 0x16B77,
0x16B7D, 0x16B8F,
},
}
m["Hmnp"] = process_ranges{
"ဏေခေါန် ၜေအ်ချိုဨ မောန်",
33712499,
"alphabet",
ranges = {
0x1E100, 0x1E12C,
0x1E130, 0x1E13D,
0x1E140, 0x1E149,
0x1E14E, 0x1E14F,
},
}
m["Hung"] = process_ranges{
"ဟာန်ဂါရေဝ်တြေံ",
446224,
"alphabet",
aliases = {"Hungarian runic"},
ranges = {
0x10C80, 0x10CB2,
0x10CC0, 0x10CF2,
0x10CFA, 0x10CFF,
},
capitalized = true,
direction = "rtl",
}
m["Ibrnn"] = {
"Northeastern Iberian",
1113155,
"semisyllabary",
ietf_subtag = "Zzzz",
-- Not in Unicode
}
m["Ibrns"] = {
"Southeastern Iberian",
2305351,
"semisyllabary",
ietf_subtag = "Zzzz",
-- Not in Unicode
}
m["Image"] = {
-- To be used to avoid any formatting or link processing
"Image-rendered",
478798,
-- This should not have any characters listed
ietf_subtag = "Zyyy",
translit = false,
character_category = false, -- none
}
m["Inds"] = {
"Indus",
601388,
aliases = {"Harappan", "Indus Valley"},
}
m["Ipach"] = {
"International Phonetic Alphabet",
21204,
aliases = {"IPA"},
ietf_subtag = "Latn",
}
m["Ital"] = process_ranges{
"ခစေၚ်တြေံ",
4891256,
"alphabet",
ranges = {
0x10300, 0x10323,
0x1032D, 0x1032F,
},
}
m["Java"] = process_ranges{
"ဂျာဗာ",
879704,
"abugida",
ranges = {
0xA980, 0xA9CD,
0xA9CF, 0xA9D9,
0xA9DE, 0xA9DF,
},
}
m["Jurc"] = {
"Jurchen",
912240,
"logography",
spaces = false,
}
m["Kali"] = process_ranges{
"ကယျာလဳ",
4919239,
"abugida",
ranges = {
0xA900, 0xA92F,
},
}
m["Kana"] = process_ranges{
"ခတခဏ",
82946,
"syllabary",
ranges = {
0x3001, 0x3003,
0x3008, 0x3011,
0x3013, 0x301F,
0x3030, 0x3035,
0x3037, 0x3037,
0x303C, 0x303D,
0x3099, 0x309C,
0x30A0, 0x30FF,
0x31F0, 0x31FF,
0x32D0, 0x32FE,
0x3300, 0x3357,
0xFE45, 0xFE46,
0xFF61, 0xFF9F,
0x1AFF0, 0x1AFF3,
0x1AFF5, 0x1AFFB,
0x1AFFD, 0x1AFFE,
0x1B000, 0x1B000,
0x1B120, 0x1B122,
0x1B155, 0x1B155,
0x1B164, 0x1B167,
},
spaces = false,
}
m["Kawi"] = process_ranges{
"ခါဝဳ",
975802,
"abugida",
ranges = {
0x11F00, 0x11F10,
0x11F12, 0x11F3A,
0x11F3E, 0x11F5A,
},
}
m["Khar"] = process_ranges{
"ခါရဝ်သတဳ",
1161266,
"abugida",
ranges = {
0x10A00, 0x10A03,
0x10A05, 0x10A06,
0x10A0C, 0x10A13,
0x10A15, 0x10A17,
0x10A19, 0x10A35,
0x10A38, 0x10A3A,
0x10A3F, 0x10A48,
0x10A50, 0x10A58,
},
direction = "rtl",
}
m["Khmr"] = process_ranges{
"ခမေန်",
1054190,
"abugida",
ranges = {
0x1780, 0x17DD,
0x17E0, 0x17E9,
0x17F0, 0x17F9,
0x19E0, 0x19FF,
},
spaces = false,
normalizationFixes = handle_normalization_fixes{
from = {"ឣ", "ឤ"},
to = {"អ", "អា"}
},
}
m["Khoj"] = process_ranges{
"ခုဒ်သကဳ",
1740656,
"abugida",
ranges = {
0x0AE6, 0x0AEF,
0xA830, 0xA839,
0x11200, 0x11211,
0x11213, 0x11241,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑈀𑈬𑈱", "𑈀𑈬", "𑈀𑈱", "𑈀𑈳", "𑈁𑈱", "𑈆𑈬", "𑈬𑈰", "𑈬𑈱", "𑉀𑈮"},
to = {"𑈇", "𑈁", "𑈅", "𑈇", "𑈇", "𑈃", "𑈲", "𑈳", "𑈂"}
},
}
m["Khomt"] = {
"Khom Thai",
13023788,
"abugida",
-- Not in Unicode
}
m["Kitl"] = {
"Khitan large",
6401797,
"logography",
spaces = false,
}
m["Kits"] = process_ranges{
"Khitan small",
6401800,
"logography, syllabary",
ranges = {
0x16FE4, 0x16FE4,
0x18B00, 0x18CD5,
0x18CFF, 0x18CFF,
},
spaces = false,
}
m["Knda"] = process_ranges{
"ကာန်နာဒါ",
839666,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0C80, 0x0C8C,
0x0C8E, 0x0C90,
0x0C92, 0x0CA8,
0x0CAA, 0x0CB3,
0x0CB5, 0x0CB9,
0x0CBC, 0x0CC4,
0x0CC6, 0x0CC8,
0x0CCA, 0x0CCD,
0x0CD5, 0x0CD6,
0x0CDD, 0x0CDE,
0x0CE0, 0x0CE3,
0x0CE6, 0x0CEF,
0x0CF1, 0x0CF3,
0x1CD0, 0x1CD0,
0x1CD2, 0x1CD3,
0x1CDA, 0x1CDA,
0x1CF2, 0x1CF2,
0x1CF4, 0x1CF4,
0xA830, 0xA835,
},
normalizationFixes = handle_normalization_fixes{
from = {"ಉಾ", "ಋಾ", "ಒೌ"},
to = {"ಊ", "ೠ", "ಔ"}
},
}
m["Kpel"] = {
"Kpelle",
1586299,
"syllabary",
-- Not in Unicode
}
m["Krai"] = process_ranges{
"Kirat Rai",
123173834,
"abugida",
aliases = {"Rai", "Khambu Rai", "Rai Barṇamālā", "Kirat Khambu Rai"},
ranges = {
0x16D40, 0x16D79,
},
}
m["Kthi"] = process_ranges{
"ကေတဳ",
1253814,
"abugida",
ranges = {
0x0966, 0x096F,
0xA830, 0xA839,
0x11080, 0x110C2,
0x110CD, 0x110CD,
},
}
m["Kulit"] = {
"Kulitan",
6443044,
"abugida",
-- Not in Unicode
}
m["Lana"] = process_ranges{
"သေံဃိန်",
1314503,
"abugida",
aliases = {"Tham", "Tua Mueang", "Lanna"},
ranges = {
0x1A20, 0x1A5E,
0x1A60, 0x1A7C,
0x1A7F, 0x1A89,
0x1A90, 0x1A99,
0x1AA0, 0x1AAD,
},
spaces = false,
}
m["Laoo"] = process_ranges{
"သေံလေဴ",
1815229,
"abugida",
ranges = {
0x0E81, 0x0E82,
0x0E84, 0x0E84,
0x0E86, 0x0E8A,
0x0E8C, 0x0EA3,
0x0EA5, 0x0EA5,
0x0EA7, 0x0EBD,
0x0EC0, 0x0EC4,
0x0EC6, 0x0EC6,
0x0EC8, 0x0ECE,
0x0ED0, 0x0ED9,
0x0EDC, 0x0EDF,
},
spaces = false,
}
m["Latn"] = process_ranges{
"လေပ်တဲၚ်",
8229,
"alphabet",
aliases = {"Roman"},
ranges = {
0x0041, 0x005A,
0x0061, 0x007A,
0x00AA, 0x00AA,
0x00BA, 0x00BA,
0x00C0, 0x00D6,
0x00D8, 0x00F6,
0x00F8, 0x02B8,
0x02C0, 0x02C1,
0x02E0, 0x02E4,
0x0363, 0x036F,
0x0485, 0x0486,
0x0951, 0x0952,
0x10FB, 0x10FB,
0x1D00, 0x1D25,
0x1D2C, 0x1D5C,
0x1D62, 0x1D65,
0x1D6B, 0x1D77,
0x1D79, 0x1DBE,
0x1DF8, 0x1DF8,
0x1E00, 0x1EFF,
0x202F, 0x202F,
0x2071, 0x2071,
0x207F, 0x207F,
0x2090, 0x209C,
0x20F0, 0x20F0,
0x2100, 0x2125,
0x2128, 0x2128,
0x212A, 0x2134,
0x2139, 0x213B,
0x2141, 0x214E,
0x2160, 0x2188,
0x2C60, 0x2C7F,
0xA700, 0xA707,
0xA722, 0xA787,
0xA78B, 0xA7CD,
0xA7D0, 0xA7D1,
0xA7D3, 0xA7D3,
0xA7D5, 0xA7DC,
0xA7F2, 0xA7FF,
0xA92E, 0xA92E,
0xAB30, 0xAB5A,
0xAB5C, 0xAB64,
0xAB66, 0xAB69,
0xFB00, 0xFB06,
0xFF21, 0xFF3A,
0xFF41, 0xFF5A,
0x10780, 0x10785,
0x10787, 0x107B0,
0x107B2, 0x107BA,
0x1DF00, 0x1DF1E,
0x1DF25, 0x1DF2A,
},
varieties = {"Rumi", "Romaji", "Rōmaji", "Romaja"},
capitalized = true,
translit = false,
}
m["Latf"] = {
"Fraktur",
148443,
m["Latn"][3],
ranges = m["Latn"].ranges,
characters = m["Latn"].characters,
otherNames = {"Blackletter"}, -- Blackletter is actually the parent "script"
capitalized = m["Latn"].capitalized,
translit = m["Latn"].translit,
parent = "Latn",
}
m["Latg"] = {
"Gaelic",
1432616,
m["Latn"][3],
ranges = m["Latn"].ranges,
characters = m["Latn"].characters,
otherNames = {"Irish"},
capitalized = m["Latn"].capitalized,
translit = m["Latn"].translit,
parent = "Latn",
}
m["pjt-Latn"] = {
"လေပ်တဲၚ်",
nil,
m["Latn"][3],
ranges = m["Latn"].ranges,
characters = m["Latn"].characters,
capitalized = m["Latn"].capitalized,
translit = m["Latn"].translit,
parent = "Latn",
}
m["Leke"] = {
"Leke",
19572613,
"abugida",
-- Not in Unicode
}
m["Lepc"] = process_ranges{
"လပ်ချာ",
1481626,
"abugida",
aliases = {"Róng"},
ranges = {
0x1C00, 0x1C37,
0x1C3B, 0x1C49,
0x1C4D, 0x1C4F,
},
}
m["Limb"] = process_ranges{
"လေန်ၜေါအ်",
933796,
"abugida",
ranges = {
0x0965, 0x0965,
0x1900, 0x191E,
0x1920, 0x192B,
0x1930, 0x193B,
0x1940, 0x1940,
0x1944, 0x194F,
},
}
m["Lina"] = process_ranges{
"လေန်နဳယျာ (က)",
30972,
ranges = {
0x10107, 0x10133,
0x10600, 0x10736,
0x10740, 0x10755,
0x10760, 0x10767,
},
}
m["Linb"] = process_ranges{
"လေန်နဳယျာ (ခ)",
190102,
ranges = {
0x10000, 0x1000B,
0x1000D, 0x10026,
0x10028, 0x1003A,
0x1003C, 0x1003D,
0x1003F, 0x1004D,
0x10050, 0x1005D,
0x10080, 0x100FA,
0x10100, 0x10102,
0x10107, 0x10133,
0x10137, 0x1013F,
},
}
m["Lisu"] = process_ranges{
"လဳသေုန်",
1194621,
"alphabet",
aliases = {"Old Lisu", "Lisu"},
ranges = {
0x300A, 0x300B,
0xA4D0, 0xA4FF,
0x11FB0, 0x11FB0,
},
normalizationFixes = handle_normalization_fixes{
from = {"['’]", "[.ꓸ][.ꓸ]", "[.ꓸ][,ꓹ]"},
to = {"ʼ", "ꓺ", "ꓻ"}
},
}
m["Loma"] = {
"Loma",
13023816,
"syllabary",
-- Not in Unicode
}
m["Lyci"] = process_ranges{
"လာဲသဳယာန်",
913587,
"alphabet",
ranges = {
0x10280, 0x1029C,
},
}
m["Lydi"] = process_ranges{
"လဳဒဳဒါန်",
4261300,
"alphabet",
ranges = {
0x10920, 0x10939,
0x1093F, 0x1093F,
},
direction = "rtl",
}
m["Mahj"] = process_ranges{
"မဟာဂျနဳ",
6732850,
"abugida",
ranges = {
0x0964, 0x096F,
0xA830, 0xA839,
0x11150, 0x11176,
},
}
m["Maka"] = process_ranges{
"Makasar",
72947229,
"abugida",
aliases = {"Old Makasar"},
ranges = {
0x11EE0, 0x11EF8,
},
}
m["Mand"] = process_ranges{
"Mandaic",
1812130,
aliases = {"Mandaean"},
ranges = {
0x0640, 0x0640,
0x0840, 0x085B,
0x085E, 0x085E,
},
direction = "rtl",
}
m["Mani"] = process_ranges{
"Manichaean",
3544702,
"abjad",
ranges = {
0x0640, 0x0640,
0x10AC0, 0x10AE6,
0x10AEB, 0x10AF6,
},
direction = "rtl",
}
m["Marc"] = process_ranges{
"Marchen",
72403709,
"abugida",
ranges = {
0x11C70, 0x11C8F,
0x11C92, 0x11CA7,
0x11CA9, 0x11CB6,
},
}
m["Maya"] = process_ranges{
"မာယျာ",
211248,
aliases = {"Maya hieroglyphic", "Mayan", "Mayan hieroglyphic"},
ranges = {
0x1D2E0, 0x1D2F3,
},
}
m["Medf"] = process_ranges{
"Medefaidrin",
1519764,
aliases = {"Oberi Okaime", "Oberi Ɔkaimɛ"},
ranges = {
0x16E40, 0x16E9A,
},
capitalized = true,
}
m["Mend"] = process_ranges{
"Mende",
951069,
aliases = {"Mende Kikakui"},
ranges = {
0x1E800, 0x1E8C4,
0x1E8C7, 0x1E8D6,
},
direction = "rtl",
}
m["Merc"] = process_ranges{
"Meroitic cursive",
73028124,
"abugida",
ranges = {
0x109A0, 0x109B7,
0x109BC, 0x109CF,
0x109D2, 0x109FF,
},
direction = "rtl",
}
m["Mero"] = process_ranges{
"Meroitic hieroglyphic",
73028623,
"abugida",
ranges = {
0x10980, 0x1099F,
},
direction = "rtl",
wikipedia_article = "Meroitic hieroglyphs",
}
m["Mlym"] = process_ranges{
"မလေဝ်ယျလာမ်",
1164129,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0D00, 0x0D0C,
0x0D0E, 0x0D10,
0x0D12, 0x0D44,
0x0D46, 0x0D48,
0x0D4A, 0x0D4F,
0x0D54, 0x0D63,
0x0D66, 0x0D7F,
0x1CDA, 0x1CDA,
0x1CF2, 0x1CF2,
0xA830, 0xA832,
},
normalizationFixes = handle_normalization_fixes{
from = {"ഇൗ", "ഉൗ", "എെ", "ഒാ", "ഒൗ", "ക്", "ണ്", "ന്റ", "ന്", "മ്", "യ്", "ര്", "ല്", "ള്", "ഴ്", "െെ", "ൻ്റ"},
to = {"ഈ", "ഊ", "ഐ", "ഓ", "ഔ", "ൿ", "ൺ", "ൻറ", "ൻ", "ൔ", "ൕ", "ർ", "ൽ", "ൾ", "ൖ", "ൈ", "ന്റ"}
},
}
m["Modi"] = process_ranges{
"မဝ်ဒဳ",
1703713,
"abugida",
ranges = {
0xA830, 0xA839,
0x11600, 0x11644,
0x11650, 0x11659,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑘀𑘹", "𑘀𑘺", "𑘁𑘹", "𑘁𑘺"},
to = {"𑘊", "𑘋", "𑘌", "𑘍"}
},
}
m["Mong"] = process_ranges{
"အုဲဂူစေံ",
1055705,
"alphabet",
aliases = {"Mongol bichig", "Hudum Mongol bichig"},
ranges = {
0x1800, 0x1805,
0x180A, 0x1819,
0x1820, 0x1842,
0x1878, 0x1878,
0x1880, 0x1897,
0x18A6, 0x18A6,
0x18A9, 0x18A9,
0x200C, 0x200D,
0x202F, 0x202F,
0x3001, 0x3002,
0x3008, 0x300B,
0x11660, 0x11668,
},
direction = "vertical-ltr",
}
m["mnc-Mong"] = process_ranges{
"မာန်ချူ",
122888,
m["Mong"][3],
ranges = {
0x1801, 0x1801,
0x1804, 0x1804,
0x1808, 0x180F,
0x1820, 0x1820,
0x1823, 0x1823,
0x1828, 0x182A,
0x182E, 0x1830,
0x1834, 0x1838,
0x183A, 0x183A,
0x185D, 0x185D,
0x185F, 0x1861,
0x1864, 0x1869,
0x186C, 0x1871,
0x1873, 0x1877,
0x1880, 0x1888,
0x188F, 0x188F,
0x189A, 0x18A5,
0x18A8, 0x18A8,
0x18AA, 0x18AA,
0x200C, 0x200D,
0x202F, 0x202F,
},
direction = "vertical-ltr",
parent = "Mong",
}
m["sjo-Mong"] = process_ranges{
"Xibe",
113624153,
m["Mong"][3],
aliases = {"Sibe"},
ranges = {
0x1804, 0x1804,
0x1807, 0x1807,
0x180A, 0x180F,
0x1820, 0x1820,
0x1823, 0x1823,
0x1828, 0x1828,
0x182A, 0x182A,
0x182E, 0x1830,
0x1834, 0x1838,
0x183A, 0x183A,
0x185D, 0x1872,
0x200C, 0x200D,
0x202F, 0x202F,
},
direction = "vertical-ltr",
parent = "mnc-Mong",
}
m["xwo-Mong"] = process_ranges{
"တံလိက်ခလေဲ",
529085,
m["Mong"][3],
aliases = {"Todo", "Todo bichig"},
ranges = {
0x1800, 0x1801,
0x1804, 0x1806,
0x180A, 0x1820,
0x1828, 0x1828,
0x182F, 0x1831,
0x1834, 0x1834,
0x1837, 0x1838,
0x183A, 0x183B,
0x1840, 0x1840,
0x1843, 0x185C,
0x1880, 0x1887,
0x1889, 0x188F,
0x1894, 0x1894,
0x1896, 0x1899,
0x18A7, 0x18A7,
0x200C, 0x200D,
0x202F, 0x202F,
0x11669, 0x1166C,
},
direction = "vertical-ltr",
parent = "Mong",
}
m["Moon"] = {
"Moon",
918391,
"alphabet",
aliases = {"Moon System of Embossed Reading", "Moon type", "Moon writing", "Moon alphabet", "Moon code"},
-- Not in Unicode
}
m["Morse"] = {
"Morse code",
79897,
ietf_subtag = "Zsym",
}
m["Mroo"] = process_ranges{
"Mru",
75919253,
aliases = {"Mro", "Mrung"},
ranges = {
0x16A40, 0x16A5E,
0x16A60, 0x16A69,
0x16A6E, 0x16A6F,
},
}
m["Mtei"] = process_ranges{
"မဳတဳ မာယေတ်",
2981413,
"abugida",
aliases = {"Meetei Mayek", "Manipuri"},
ranges = {
0xAAE0, 0xAAF6,
0xABC0, 0xABED,
0xABF0, 0xABF9,
},
}
m["Mult"] = process_ranges{
"Multani",
17047906,
"abugida",
ranges = {
0x0A66, 0x0A6F,
0x11280, 0x11286,
0x11288, 0x11288,
0x1128A, 0x1128D,
0x1128F, 0x1129D,
0x1129F, 0x112A9,
},
}
m["Music"] = process_ranges{
"musical notation",
233861,
"pictography",
ranges = {
0x2669, 0x266F,
0x1D100, 0x1D126,
0x1D129, 0x1D1EA,
},
ietf_subtag = "Zsym",
translit = false,
}
m["Mymr"] = process_ranges{
"မန်-ဗၟာ",
43887939,
"abugida",
aliases = {"Myanmar"},
ranges = {
0x1000, 0x109F,
0xA92E, 0xA92E,
0xA9E0, 0xA9FE,
0xAA60, 0xAA7F,
0x116D0, 0x116E3,
},
spaces = false,
}
m["Nagm"] = process_ranges{
"Mundari Bani",
106917274,
"alphabet",
aliases = {"Nag Mundari"},
ranges = {
0x1E4D0, 0x1E4F9,
},
}
m["Nand"] = process_ranges{
"နာန်ဒဳနာဂါရေဝ်",
6963324,
"abugida",
ranges = {
0x0964, 0x0965,
0x0CE6, 0x0CEF,
0x1CE9, 0x1CE9,
0x1CF2, 0x1CF2,
0x1CFA, 0x1CFA,
0xA830, 0xA835,
0x119A0, 0x119A7,
0x119AA, 0x119D7,
0x119DA, 0x119E4,
},
}
m["Narb"] = process_ranges{
"Ancient North Arabian",
1472213,
"abjad",
aliases = {"Old North Arabian"},
ranges = {
0x10A80, 0x10A9F,
},
direction = "rtl",
}
m["Nbat"] = process_ranges{
"Nabataean",
855624,
"abjad",
aliases = {"Nabatean"},
ranges = {
0x10880, 0x1089E,
0x108A7, 0x108AF,
},
direction = "rtl",
}
m["Newa"] = process_ranges{
"နဳဝါ",
7237292,
"abugida",
aliases = {"Newar", "Newari", "Prachalit Nepal"},
ranges = {
0x11400, 0x1145B,
0x1145D, 0x11461,
},
}
m["Nkdb"] = {
"Dongba",
1190953,
"pictography",
aliases = {"Naxi Dongba", "Nakhi Dongba", "Tomba", "Tompa", "Mo-so"},
spaces = false,
-- Not in Unicode
}
m["Nkgb"] = {
"Geba",
731189,
"syllabary",
aliases = {"Nakhi Geba", "Naxi Geba"},
spaces = false,
-- Not in Unicode
}
m["Nkoo"] = process_ranges{
"အိန်'ဂဝ်",
1062587,
"alphabet",
ranges = {
0x060C, 0x060C,
0x061B, 0x061B,
0x061F, 0x061F,
0x07C0, 0x07FA,
0x07FD, 0x07FF,
0xFD3E, 0xFD3F,
},
direction = "rtl",
}
m["None"] = {
"unspecified",
nil,
-- This should not have any characters listed
ietf_subtag = "Zyyy",
translit = false,
character_category = false, -- none
}
m["Nshu"] = process_ranges{
"Nüshu",
56436,
"syllabary",
aliases = {"Nushu"},
ranges = {
0x16FE1, 0x16FE1,
0x1B170, 0x1B2FB,
},
spaces = false,
}
m["Ogam"] = process_ranges{
"Ogham",
184661,
ranges = {
0x1680, 0x169C,
},
}
m["Olck"] = process_ranges{
"Ol Chiki",
201688,
aliases = {"Ol Chemetʼ", "Ol", "Santali"},
ranges = {
0x1C50, 0x1C7F,
},
}
m["Onao"] = process_ranges{
"Ol Onal",
108607084,
"alphabet",
ranges = {
0x0964, 0x0965,
0x1E5D0, 0x1E5FA,
0x1E5FF, 0x1E5FF,
},
}
m["Orkh"] = process_ranges{
"အဝ်ခန်ရုန်",
5058305,
aliases = {"Orkhon runic"},
ranges = {
0x10C00, 0x10C48,
},
direction = "rtl",
}
m["Orya"] = process_ranges{
"အဝ်ရေဝ်ယာ",
1760127,
"abugida",
aliases = {"Oriya"},
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0B01, 0x0B03,
0x0B05, 0x0B0C,
0x0B0F, 0x0B10,
0x0B13, 0x0B28,
0x0B2A, 0x0B30,
0x0B32, 0x0B33,
0x0B35, 0x0B39,
0x0B3C, 0x0B44,
0x0B47, 0x0B48,
0x0B4B, 0x0B4D,
0x0B55, 0x0B57,
0x0B5C, 0x0B5D,
0x0B5F, 0x0B63,
0x0B66, 0x0B77,
0x1CDA, 0x1CDA,
0x1CF2, 0x1CF2,
},
normalizationFixes = handle_normalization_fixes{
from = {"ଅା", "ଏୗ", "ଓୗ"},
to = {"ଆ", "ଐ", "ଔ"}
},
}
m["Osge"] = process_ranges{
"Osage",
7105529,
ranges = {
0x104B0, 0x104D3,
0x104D8, 0x104FB,
},
capitalized = true,
}
m["Osma"] = process_ranges{
"Osmanya",
1377866,
ranges = {
0x10480, 0x1049D,
0x104A0, 0x104A9,
},
}
m["Ougr"] = process_ranges{
"ဝဳဂါယ်တြေံ",
1998938,
"abjad, alphabet",
ranges = {
0x0640, 0x0640,
0x10AF2, 0x10AF2,
0x10F70, 0x10F89,
},
-- This should ideally be "vertical-ltr", but getting the CSS right is tricky because it's right-to-left horizontally, but left-to-right vertically. Currently, displaying it vertically causes it to display bottom-to-top.
direction = "rtl",
}
m["Palm"] = process_ranges{
"ပါမာဲရၚ်",
17538100,
ranges = {
0x10860, 0x1087F,
},
direction = "rtl",
}
m["Pauc"] = process_ranges{
"ဖါဲသေၚ်အော",
25339852,
ranges = {
0x11AC0, 0x11AF8,
},
}
m["Pcun"] = {
"Proto-Cuneiform",
1650699,
"pictography",
-- Not in Unicode
}
m["Pelm"] = {
"Proto-Elamite",
56305763,
"pictography",
-- Not in Unicode
}
m["Perm"] = process_ranges{
"ပါမေတ်တြေံ",
147899,
ranges = {
0x0483, 0x0483,
0x10350, 0x1037A,
},
}
m["Phag"] = process_ranges{
"ဖှတ်-ပါ",
822836,
"abugida",
ranges = {
0x1802, 0x1803,
0x1805, 0x1805,
0x200C, 0x200D,
0x202F, 0x202F,
0x3002, 0x3002,
0xA840, 0xA877,
},
direction = "vertical-ltr",
}
m["Phli"] = process_ranges{
"ပါလာဝဳ လိက်ဇြေဟ်",
24089793,
"abjad",
ranges = {
0x10B60, 0x10B72,
0x10B78, 0x10B7F,
},
direction = "rtl",
}
m["Phlp"] = process_ranges{
"ပါလာဝဳ သဝ်ဒါန်",
7253954,
"abjad",
ranges = {
0x0640, 0x0640,
0x10B80, 0x10B91,
0x10B99, 0x10B9C,
0x10BA9, 0x10BAF,
},
direction = "rtl",
}
m["Phlv"] = {
"Book Pahlavi",
72403118,
"abjad",
direction = "rtl",
wikipedia_article = "Pahlavi scripts#Book Pahlavi",
-- Not in Unicode
}
m["Phnx"] = process_ranges{
"ဖဳနေတ်ယှေန်",
26752,
"abjad",
ranges = {
0x10900, 0x1091B,
0x1091F, 0x1091F,
},
direction = "rtl",
}
m["Plrd"] = process_ranges{
"Pollard",
601734,
"abugida",
aliases = {"Miao"},
ranges = {
0x16F00, 0x16F4A,
0x16F4F, 0x16F87,
0x16F8F, 0x16F9F,
},
}
m["Prti"] = process_ranges{
"Inscriptional Parthian",
13023804,
ranges = {
0x10B40, 0x10B55,
0x10B58, 0x10B5F,
},
direction = "rtl",
}
m["Psin"] = {
"Proto-Sinaitic",
1065250,
"abjad",
direction = "rtl",
-- Not in Unicode
}
m["Ranj"] = {
"Ranjana",
2385276,
"abugida",
-- Not in Unicode
}
m["Rjng"] = process_ranges{
"ရေဂျေန်",
2007960,
"abugida",
ranges = {
0xA930, 0xA953,
0xA95F, 0xA95F,
},
}
m["Rohg"] = process_ranges{
"Hanifi Rohingya",
21028705,
"alphabet",
ranges = {
0x060C, 0x060C,
0x061B, 0x061B,
0x061F, 0x061F,
0x0640, 0x0640,
0x06D4, 0x06D4,
0x10D00, 0x10D27,
0x10D30, 0x10D39,
},
direction = "rtl",
}
m["Roro"] = {
"Rongorongo",
209764,
-- Not in Unicode
}
m["Rumin"] = process_ranges{
"Rumi numerals",
nil,
ranges = {
0x10E60, 0x10E7E,
},
ietf_subtag = "Arab",
}
m["Runr"] = process_ranges{
"ရူနေတ်",
82996,
"alphabet",
ranges = {
0x16A0, 0x16EA,
0x16EE, 0x16F8,
},
}
m["Samr"] = process_ranges{
"သျမာရိဠူ",
1550930,
"abjad",
ranges = {
0x0800, 0x082D,
0x0830, 0x083E,
},
direction = "rtl",
}
m["Sarb"] = process_ranges{
"Ancient South Arabian",
446074,
"abjad",
aliases = {"Old South Arabian"},
ranges = {
0x10A60, 0x10A7F,
},
direction = "rtl",
}
m["Saur"] = process_ranges{
"သေဝ်ရာတ်သာတ်တရာ",
3535165,
"abugida",
ranges = {
0xA880, 0xA8C5,
0xA8CE, 0xA8D9,
},
}
m["Semap"] = {
"flag semaphore",
250796,
"pictography",
ietf_subtag = "Zsym",
}
m["Sgnw"] = process_ranges{
"SignWriting",
1497335,
"pictography",
aliases = {"Sutton SignWriting"},
ranges = {
0x1D800, 0x1DA8B,
0x1DA9B, 0x1DA9F,
0x1DAA1, 0x1DAAF,
},
translit = false,
}
m["Shaw"] = process_ranges{
"သျှဗဳယာန်",
1970098,
aliases = {"Shaw"},
ranges = {
0x10450, 0x1047F,
},
}
m["Shrd"] = process_ranges{
"ဃှဳဝါတာ",
2047117,
"abugida",
ranges = {
0x0951, 0x0951,
0x1CD7, 0x1CD7,
0x1CD9, 0x1CD9,
0x1CDC, 0x1CDD,
0x1CE0, 0x1CE0,
0xA830, 0xA835,
0xA838, 0xA838,
0x11180, 0x111DF,
},
}
m["Shui"] = {
"Sui",
752854,
"logography",
spaces = false,
-- Not in Unicode
}
m["Sidd"] = process_ranges{
"သေတ်ဒေါန်",
250379,
"abugida",
ranges = {
0x11580, 0x115B5,
0x115B8, 0x115DD,
},
}
m["Sidt"] = {
"Sidetic",
36659,
"alphabet",
direction = "rtl",
-- Not in Unicode
}
m["Sind"] = process_ranges{
"ဒူဒါဝါဒဳ",
6402810,
"abugida",
aliases = {"Khudawadi"},
ranges = {
0x0964, 0x0965,
0xA830, 0xA839,
0x112B0, 0x112EA,
0x112F0, 0x112F9,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑊰𑋠", "𑊰𑋥", "𑊰𑋦", "𑊰𑋧", "𑊰𑋨"},
to = {"𑊱", "𑊶", "𑊷", "𑊸", "𑊹"}
},
}
m["Sinh"] = process_ranges{
"သဳရိလၚ်္ကာ",
1574992,
"abugida",
aliases = {"Sinhala"},
ranges = {
0x0964, 0x0965,
0x0D81, 0x0D83,
0x0D85, 0x0D96,
0x0D9A, 0x0DB1,
0x0DB3, 0x0DBB,
0x0DBD, 0x0DBD,
0x0DC0, 0x0DC6,
0x0DCA, 0x0DCA,
0x0DCF, 0x0DD4,
0x0DD6, 0x0DD6,
0x0DD8, 0x0DDF,
0x0DE6, 0x0DEF,
0x0DF2, 0x0DF4,
0x1CF2, 0x1CF2,
0x111E1, 0x111F4,
},
normalizationFixes = handle_normalization_fixes{
from = {"අා", "අැ", "අෑ", "උෟ", "ඍෘ", "ඏෟ", "එ්", "එෙ", "ඔෟ", "ෘෘ"},
to = {"ආ", "ඇ", "ඈ", "ඌ", "ඎ", "ඐ", "ඒ", "ඓ", "ඖ", "ෲ"}
},
}
m["Sogd"] = process_ranges{
"သတ်ဂျဳယာန်",
578359,
"abjad",
ranges = {
0x0640, 0x0640,
0x10F30, 0x10F59,
},
direction = "rtl",
}
m["Sogo"] = process_ranges{
"သတ်ဂျဳယာန်တြေံ",
72403254,
"abjad",
ranges = {
0x10F00, 0x10F27,
},
direction = "rtl",
}
m["Sora"] = process_ranges{
"Sorang Sompeng",
7563292,
aliases = {"Sora Sompeng"},
ranges = {
0x110D0, 0x110E8,
0x110F0, 0x110F9,
},
}
m["Soyo"] = process_ranges{
"သဝ်ယွေန်ဗဝ်",
8009382,
"abugida",
ranges = {
0x11A50, 0x11AA2,
},
}
m["Sund"] = process_ranges{
"သာန်ဓနဳ",
51589,
"abugida",
ranges = {
0x1B80, 0x1BBF,
0x1CC0, 0x1CC7,
},
}
m["Sunu"] = process_ranges{
"Sunuwar",
109984965,
"alphabet",
ranges = {
0x11BC0, 0x11BE1,
0x11BF0, 0x11BF9,
},
}
m["Sylo"] = process_ranges{
"Sylheti Nagri",
144128,
"abugida",
aliases = {"Sylheti Nāgarī", "Syloti Nagri"},
ranges = {
0x0964, 0x0965,
0x09E6, 0x09EF,
0xA800, 0xA82C,
},
}
m["Syrc"] = process_ranges{
"သဳရဳယျာ",
26567,
"abjad", -- more precisely, impure abjad
ranges = {
0x060C, 0x060C,
0x061B, 0x061C,
0x061F, 0x061F,
0x0640, 0x0640,
0x064B, 0x0655,
0x0670, 0x0670,
0x0700, 0x070D,
0x070F, 0x074A,
0x074D, 0x074F,
0x0860, 0x086A,
0x1DF8, 0x1DF8,
0x1DFA, 0x1DFA,
},
direction = "rtl",
}
-- Syre, Syrj, Syrn are apparently subsumed into Syrc; discuss if this causes issues
m["Tagb"] = process_ranges{
"တဂ်ဗါန်ဝါ",
977444,
"abugida",
ranges = {
0x1735, 0x1736,
0x1760, 0x176C,
0x176E, 0x1770,
0x1772, 0x1773,
},
}
m["Takr"] = process_ranges{
"တာဂရေဝ်",
759202,
"abugida",
ranges = {
0x0964, 0x0965,
0xA830, 0xA839,
0x11680, 0x116B9,
0x116C0, 0x116C9,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑚀𑚭", "𑚀𑚴", "𑚀𑚵", "𑚆𑚲"},
to = {"𑚁", "𑚈", "𑚉", "𑚇"}
},
}
m["Tale"] = process_ranges{
"သေံတာဲခေါၚ်",
2566326,
"abugida",
aliases = {"Tai Nuea", "New Tai Nüa", "New Tai Nuea", "Dehong Dai", "Tai Dehong", "Tai Le"},
ranges = {
0x1040, 0x1049,
0x1950, 0x196D,
0x1970, 0x1974,
},
spaces = false,
}
m["Talu"] = process_ranges{
"သေံလုတၟိ",
3498863,
"abugida",
ranges = {
0x1980, 0x19AB,
0x19B0, 0x19C9,
0x19D0, 0x19DA,
0x19DE, 0x19DF,
},
spaces = false,
}
m["Taml"] = process_ranges{
"တမဳလ်",
26803,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0B82, 0x0B83,
0x0B85, 0x0B8A,
0x0B8E, 0x0B90,
0x0B92, 0x0B95,
0x0B99, 0x0B9A,
0x0B9C, 0x0B9C,
0x0B9E, 0x0B9F,
0x0BA3, 0x0BA4,
0x0BA8, 0x0BAA,
0x0BAE, 0x0BB9,
0x0BBE, 0x0BC2,
0x0BC6, 0x0BC8,
0x0BCA, 0x0BCD,
0x0BD0, 0x0BD0,
0x0BD7, 0x0BD7,
0x0BE6, 0x0BFA,
0x1CDA, 0x1CDA,
0xA8F3, 0xA8F3,
0x11301, 0x11301,
0x11303, 0x11303,
0x1133B, 0x1133C,
0x11FC0, 0x11FF1,
0x11FFF, 0x11FFF,
},
normalizationFixes = handle_normalization_fixes{
from = {"அூ", "ஸ்ரீ"},
to = {"ஆ", "ஶ்ரீ"}
},
}
m["Tang"] = process_ranges{
"တာန်ဂူ",
1373610,
"logography, syllabary",
ranges = {
0x31EF, 0x31EF,
0x16FE0, 0x16FE0,
0x17000, 0x187F7,
0x18800, 0x18AFF,
0x18D00, 0x18D08,
},
spaces = false,
}
m["Tavt"] = process_ranges{
"သေံဗဳယေတ်",
11818517,
"abugida",
ranges = {
0xAA80, 0xAAC2,
0xAADB, 0xAADF,
},
spaces = false,
}
m["Tayo"] = {
"Lai Tay",
16306701,
"abugida",
aliases = {"Tai Yo"},
direction = "vertical-rtl",
-- Not in Unicode
}
m["Telu"] = process_ranges{
"တေလုဂု",
570450,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x0C00, 0x0C0C,
0x0C0E, 0x0C10,
0x0C12, 0x0C28,
0x0C2A, 0x0C39,
0x0C3C, 0x0C44,
0x0C46, 0x0C48,
0x0C4A, 0x0C4D,
0x0C55, 0x0C56,
0x0C58, 0x0C5A,
0x0C5D, 0x0C5D,
0x0C60, 0x0C63,
0x0C66, 0x0C6F,
0x0C77, 0x0C7F,
0x1CDA, 0x1CDA,
0x1CF2, 0x1CF2,
},
normalizationFixes = handle_normalization_fixes{
from = {"ఒౌ", "ఒౕ", "ిౕ", "ెౕ", "ొౕ"},
to = {"ఔ", "ఓ", "ీ", "ే", "ో"}
},
}
m["Teng"] = {
"Tengwar",
473725,
}
m["Tfng"] = process_ranges{
"တဳဖဳနေတ်",
208503,
"abjad, alphabet",
ranges = {
0x2D30, 0x2D67,
0x2D6F, 0x2D70,
0x2D7F, 0x2D7F,
},
otherNames = {"Libyco-Berber", "Berber"}, -- per Wikipedia, Libyco-Berber is the parent
}
m["Tglg"] = process_ranges{
"ဗါဲဗါဲရေန်",
812124,
"abugida",
aliases = {"Tagalog"},
varieties = {"Kur-itan"},
ranges = {
0x1700, 0x1715,
0x171F, 0x171F,
0x1735, 0x1736,
},
}
m["Thaa"] = process_ranges{
"ထဏး",
877906,
"abugida",
ranges = {
0x060C, 0x060C,
0x061B, 0x061C,
0x061F, 0x061F,
0x0660, 0x0669,
0x0780, 0x07B1,
0xFDF2, 0xFDF2,
0xFDFD, 0xFDFD,
},
direction = "rtl",
}
m["Thai"] = process_ranges{
"သေံ",
236376,
"abugida",
ranges = {
0x0E01, 0x0E3A,
0x0E40, 0x0E5B,
},
spaces = false,
}
m["Tibt"] = process_ranges{
"တိဗိတ်",
46861,
"abugida",
ranges = {
0x0F00, 0x0F47,
0x0F49, 0x0F6C,
0x0F71, 0x0F97,
0x0F99, 0x0FBC,
0x0FBE, 0x0FCC,
0x0FCE, 0x0FD4,
0x0FD9, 0x0FDA,
0x3008, 0x300B,
},
normalizationFixes = handle_normalization_fixes{
combiningClasses = {["༹"] = 1},
from = {"ཷ", "ཹ"},
to = {"ྲཱྀ", "ླཱྀ"}
},
}
m["sit-tam-Tibt"] = {
"Tamyig",
109875213,
m["Tibt"][3],
ranges = m["Tibt"].ranges,
characters = m["Tibt"].characters,
parent = "Tibt",
normalizationFixes = m["Tibt"].normalizationFixes,
}
m["Tirh"] = process_ranges{
"တိရဟုတာ",
1765752,
"abugida",
ranges = {
0x0951, 0x0952,
0x0964, 0x0965,
0x1CF2, 0x1CF2,
0xA830, 0xA839,
0x11480, 0x114C7,
0x114D0, 0x114D9,
},
normalizationFixes = handle_normalization_fixes{
from = {"𑒁𑒰", "𑒋𑒺", "𑒍𑒺", "𑒪𑒵", "𑒪𑒶"},
to = {"𑒂", "𑒌", "𑒎", "𑒉", "𑒊"}
},
}
m["Tnsa"] = process_ranges{
"Tangsa",
105576311,
"alphabet",
ranges = {
0x16A70, 0x16ABE,
0x16AC0, 0x16AC9,
},
}
m["Todr"] = process_ranges{
"Todhri",
10274731,
"alphabet",
direction = "rtl",
ranges = {
0x105C0, 0x105F3,
},
}
m["Tols"] = {
"Tolong Siki",
4459822,
"alphabet",
-- Not in Unicode
}
m["Toto"] = process_ranges{
"Toto",
104837516,
"abugida",
ranges = {
0x1E290, 0x1E2AE,
},
}
m["Tutg"] = process_ranges{
"Tigalari",
2604990,
"abugida",
aliases = {"Tulu"},
ranges = {
0x1CF2, 0x1CF2,
0x1CF4, 0x1CF4,
0xA8F1, 0xA8F1,
0x11380, 0x11389,
0x1138B, 0x1138B,
0x1138E, 0x1138E,
0x11390, 0x113B5,
0x113B7, 0x113C0,
0x113C2, 0x113C2,
0x113C5, 0x113C5,
0x113C7, 0x113CA,
0x113CC, 0x113D5,
0x113D7, 0x113D8,
0x113E1, 0x113E2,
},
}
m["Ugar"] = process_ranges{
"ယူဂရေတ်တေတ်",
332652,
"abjad",
ranges = {
0x10380, 0x1039D,
0x1039F, 0x1039F,
},
}
m["Vaii"] = process_ranges{
"ဝဲါ",
523078,
"syllabary",
ranges = {
0xA500, 0xA62B,
},
}
m["Visp"] = {
"Visible Speech",
1303365,
"alphabet",
-- Not in Unicode
}
m["Vith"] = process_ranges{
"ဝိသကူကဳ",
3301993,
"alphabet",
ranges = {
0x10570, 0x1057A,
0x1057C, 0x1058A,
0x1058C, 0x10592,
0x10594, 0x10595,
0x10597, 0x105A1,
0x105A3, 0x105B1,
0x105B3, 0x105B9,
0x105BB, 0x105BC,
},
capitalized = true,
}
m["Wara"] = process_ranges{
"ဝါရာန်ခဃှဳတဳ",
79199,
aliases = {"Warang Citi"},
ranges = {
0x118A0, 0x118F2,
0x118FF, 0x118FF,
},
capitalized = true,
}
m["Wcho"] = process_ranges{
"ဝါန်ဆေဝ်",
33713728,
"alphabet",
ranges = {
0x1E2C0, 0x1E2F9,
0x1E2FF, 0x1E2FF,
},
}
m["Wole"] = {
"Woleai",
6643710,
"syllabary",
-- Not in Unicode
}
m["Xpeo"] = process_ranges{
"ဖာသဳတြေံ",
1471822,
ranges = {
0x103A0, 0x103C3,
0x103C8, 0x103D5,
},
}
m["Xsux"] = process_ranges{
"ကြူနဳဖံၚ်",
401,
aliases = {"Sumero-Akkadian Cuneiform"},
ranges = {
0x12000, 0x12399,
0x12400, 0x1246E,
0x12470, 0x12474,
0x12480, 0x12543,
},
}
m["Yezi"] = process_ranges{
"ယဵုသဳဒိ",
13175481,
"alphabet",
ranges = {
0x060C, 0x060C,
0x061B, 0x061B,
0x061F, 0x061F,
0x0660, 0x0669,
0x10E80, 0x10EA9,
0x10EAB, 0x10EAD,
0x10EB0, 0x10EB1,
},
direction = "rtl",
}
m["Yiii"] = process_ranges{
"ယဳ",
1197646,
"syllabary",
ranges = {
0x3001, 0x3002,
0x3008, 0x3011,
0x3014, 0x301B,
0x30FB, 0x30FB,
0xA000, 0xA48C,
0xA490, 0xA4C6,
0xFF61, 0xFF65,
},
}
m["Zanb"] = process_ranges{
"ပန်ကၠၚ်ဇာနာဗဇြာ",
50809208,
"abugida",
ranges = {
0x11A00, 0x11A47,
},
}
m["Zmth"] = process_ranges{
"သၚ်္ချာလ္ပာ်သက်ခရက်သမ္တီလဝ်",
1140046,
ranges = {
0x00AC, 0x00AC,
0x00B1, 0x00B1,
0x00D7, 0x00D7,
0x00F7, 0x00F7,
0x03D0, 0x03D2,
0x03D5, 0x03D5,
0x03F0, 0x03F1,
0x03F4, 0x03F6,
0x0606, 0x0608,
0x2016, 0x2016,
0x2032, 0x2034,
0x2040, 0x2040,
0x2044, 0x2044,
0x2052, 0x2052,
0x205F, 0x205F,
0x2061, 0x2064,
0x207A, 0x207E,
0x208A, 0x208E,
0x20D0, 0x20DC,
0x20E1, 0x20E1,
0x20E5, 0x20E6,
0x20EB, 0x20EF,
0x2102, 0x2102,
0x2107, 0x2107,
0x210A, 0x2113,
0x2115, 0x2115,
0x2118, 0x211D,
0x2124, 0x2124,
0x2128, 0x2129,
0x212C, 0x212D,
0x212F, 0x2131,
0x2133, 0x2138,
0x213C, 0x2149,
0x214B, 0x214B,
0x2190, 0x21A7,
0x21A9, 0x21AE,
0x21B0, 0x21B1,
0x21B6, 0x21B7,
0x21BC, 0x21DB,
0x21DD, 0x21DD,
0x21E4, 0x21E5,
0x21F4, 0x22FF,
0x2308, 0x230B,
0x2320, 0x2321,
0x237C, 0x237C,
0x239B, 0x23B5,
0x23B7, 0x23B7,
0x23D0, 0x23D0,
0x23DC, 0x23E2,
0x25A0, 0x25A1,
0x25AE, 0x25B7,
0x25BC, 0x25C1,
0x25C6, 0x25C7,
0x25CA, 0x25CB,
0x25CF, 0x25D3,
0x25E2, 0x25E2,
0x25E4, 0x25E4,
0x25E7, 0x25EC,
0x25F8, 0x25FF,
0x2605, 0x2606,
0x2640, 0x2640,
0x2642, 0x2642,
0x2660, 0x2663,
0x266D, 0x266F,
0x27C0, 0x27FF,
0x2900, 0x2AFF,
0x2B30, 0x2B44,
0x2B47, 0x2B4C,
0xFB29, 0xFB29,
0xFE61, 0xFE66,
0xFE68, 0xFE68,
0xFF0B, 0xFF0B,
0xFF1C, 0xFF1E,
0xFF3C, 0xFF3C,
0xFF3E, 0xFF3E,
0xFF5C, 0xFF5C,
0xFF5E, 0xFF5E,
0xFFE2, 0xFFE2,
0xFFE9, 0xFFEC,
0x1D400, 0x1D454,
0x1D456, 0x1D49C,
0x1D49E, 0x1D49F,
0x1D4A2, 0x1D4A2,
0x1D4A5, 0x1D4A6,
0x1D4A9, 0x1D4AC,
0x1D4AE, 0x1D4B9,
0x1D4BB, 0x1D4BB,
0x1D4BD, 0x1D4C3,
0x1D4C5, 0x1D505,
0x1D507, 0x1D50A,
0x1D50D, 0x1D514,
0x1D516, 0x1D51C,
0x1D51E, 0x1D539,
0x1D53B, 0x1D53E,
0x1D540, 0x1D544,
0x1D546, 0x1D546,
0x1D54A, 0x1D550,
0x1D552, 0x1D6A5,
0x1D6A8, 0x1D7CB,
0x1D7CE, 0x1D7FF,
0x1EE00, 0x1EE03,
0x1EE05, 0x1EE1F,
0x1EE21, 0x1EE22,
0x1EE24, 0x1EE24,
0x1EE27, 0x1EE27,
0x1EE29, 0x1EE32,
0x1EE34, 0x1EE37,
0x1EE39, 0x1EE39,
0x1EE3B, 0x1EE3B,
0x1EE42, 0x1EE42,
0x1EE47, 0x1EE47,
0x1EE49, 0x1EE49,
0x1EE4B, 0x1EE4B,
0x1EE4D, 0x1EE4F,
0x1EE51, 0x1EE52,
0x1EE54, 0x1EE54,
0x1EE57, 0x1EE57,
0x1EE59, 0x1EE59,
0x1EE5B, 0x1EE5B,
0x1EE5D, 0x1EE5D,
0x1EE5F, 0x1EE5F,
0x1EE61, 0x1EE62,
0x1EE64, 0x1EE64,
0x1EE67, 0x1EE6A,
0x1EE6C, 0x1EE72,
0x1EE74, 0x1EE77,
0x1EE79, 0x1EE7C,
0x1EE7E, 0x1EE7E,
0x1EE80, 0x1EE89,
0x1EE8B, 0x1EE9B,
0x1EEA1, 0x1EEA3,
0x1EEA5, 0x1EEA9,
0x1EEAB, 0x1EEBB,
0x1EEF0, 0x1EEF1,
},
translit = false,
}
m["Zsym"] = process_ranges{
"သၚ်္ကေတ",
80071,
"pictography",
ranges = {
0x20DD, 0x20E0,
0x20E2, 0x20E4,
0x20E7, 0x20EA,
0x20F0, 0x20F0,
0x2100, 0x2101,
0x2103, 0x2106,
0x2108, 0x2109,
0x2114, 0x2114,
0x2116, 0x2117,
0x211E, 0x2123,
0x2125, 0x2127,
0x212A, 0x212B,
0x212E, 0x212E,
0x2132, 0x2132,
0x2139, 0x213B,
0x214A, 0x214A,
0x214C, 0x214F,
0x21A8, 0x21A8,
0x21AF, 0x21AF,
0x21B2, 0x21B5,
0x21B8, 0x21BB,
0x21DC, 0x21DC,
0x21DE, 0x21E3,
0x21E6, 0x21F3,
0x2300, 0x2307,
0x230C, 0x231F,
0x2322, 0x237B,
0x237D, 0x239A,
0x23B6, 0x23B6,
0x23B8, 0x23CF,
0x23D1, 0x23DB,
0x23E3, 0x23FF,
0x2500, 0x259F,
0x25A2, 0x25AD,
0x25B8, 0x25BB,
0x25C2, 0x25C5,
0x25C8, 0x25C9,
0x25CC, 0x25CE,
0x25D4, 0x25E1,
0x25E3, 0x25E3,
0x25E5, 0x25E6,
0x25ED, 0x25F7,
0x2600, 0x2604,
0x2607, 0x263F,
0x2641, 0x2641,
0x2643, 0x265F,
0x2664, 0x266C,
0x2670, 0x27BF,
0x2B00, 0x2B2F,
0x2B45, 0x2B46,
0x2B4D, 0x2B73,
0x2B76, 0x2B95,
0x2B97, 0x2BFF,
0x4DC0, 0x4DFF,
0x1F000, 0x1F02B,
0x1F030, 0x1F093,
0x1F0A0, 0x1F0AE,
0x1F0B1, 0x1F0BF,
0x1F0C1, 0x1F0CF,
0x1F0D1, 0x1F0F5,
0x1F300, 0x1F6D7,
0x1F6DC, 0x1F6EC,
0x1F6F0, 0x1F6FC,
0x1F700, 0x1F776,
0x1F77B, 0x1F7D9,
0x1F7E0, 0x1F7EB,
0x1F7F0, 0x1F7F0,
0x1F800, 0x1F80B,
0x1F810, 0x1F847,
0x1F850, 0x1F859,
0x1F860, 0x1F887,
0x1F890, 0x1F8AD,
0x1F8B0, 0x1F8B1,
0x1F900, 0x1FA53,
0x1FA60, 0x1FA6D,
0x1FA70, 0x1FA7C,
0x1FA80, 0x1FA88,
0x1FA90, 0x1FABD,
0x1FABF, 0x1FAC5,
0x1FACE, 0x1FADB,
0x1FAE0, 0x1FAE8,
0x1FAF0, 0x1FAF8,
0x1FB00, 0x1FB92,
0x1FB94, 0x1FBCA,
0x1FBF0, 0x1FBF9,
},
translit = false,
character_category = false, -- none
}
m["Zyyy"] = {
"undetermined",
104839687,
-- This should not have any characters listed, probably
translit = false,
character_category = false, -- none
}
m["Zzzz"] = {
"uncoded",
104839675,
-- This should not have any characters listed
translit = false,
character_category = false, -- none
}
-- These should be defined after the scripts they are composed of.
m["Hrkt"] = process_ranges{
"ကာနာ",
187659,
"syllabary",
aliases = {"Japanese syllabaries"},
ranges = union(
m["Hira"].ranges,
m["Kana"].ranges
),
spaces = false,
}
m["Jpan"] = process_ranges{
"ဂျပါန်",
190502,
"logography, syllabary",
ranges = union(
m["Hrkt"].ranges,
m["Hani"].ranges,
m["Latn"].ranges
),
spaces = false,
sort_by_scraping = true,
}
m["Kore"] = process_ranges{
"ကိုဝ်ရဳယျာ",
711797,
"logography, syllabary",
ranges = union(
m["Hang"].ranges,
m["Hani"].ranges,
m["Latn"].ranges
),
}
return require("Module:languages").finalizeData(m, "script")
gf71im7japfrtto51ukawddn8yub37t
မဝ်ဂျူ:ru-common
828
8083
399857
133608
2026-07-22T23:54:20Z
咽頭べさ
33
399857
Scribunto
text/plain
local export = {}
--[==[ intro:
Author: Benwing; some very early work by Rua and Atitarev
This module holds some commonly used functions for the Russian language. It's generally for use from other modules, not
`#invoke`, although some functions can be invoked from a template (`export.iotation()`, `export.reduce_stem()`,
`export.dereduce_stem()`, actually added to support calling from a bot script rather than from a user template; and
`export.make_unstressed()`, called from {{tl|R:ru:Vasmer}}). There may be issues when invoking such functions from
templates when transliteration is present, due to the need for the transliteration to be decomposed, as mentioned below
(all strings from Wiktionary pages are normally in composed form).
NOTE NOTE NOTE: All functions assume that transliteration (but not Russian) has had its acute and grave accents
decomposed using `export.decompose()`. This is the first thing that should be done to all user-specified
transliteration and any transliteration we compute that we expect to work with.
]==]
local m_str_utils = require("Module:string utilities")
local m_table_tools = require("Module:table tools")
-- Prevents an infinite require loop since ru-translit requires a different function in this module.
local m_ru_translit = require("Module:require when needed")("Module:ru-translit")
local m_headword_utilities = require("Module:require when needed")("Module:headword utilities")
local m_table = require("Module:require when needed")("Module:table")
local gsplit = m_str_utils.gsplit
local split = m_str_utils.split
local toNFD = mw.ustring.toNFD
local u = m_str_utils.char
local ufind = mw.ustring.find
local ugsub = mw.ustring.gsub
local ulen = m_str_utils.len
local ulower = m_str_utils.lower
local umatch = mw.ustring.match
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local usub = m_str_utils.sub
local insert = table.insert
local concat = table.concat
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local BREVE = u(0x0306) -- breve ̆
local DIA = u(0x0308) -- diaeresis = ̈
local CARON = u(0x030C) -- caron ̌
local OGONEK = u(0x0328) -- ogonek ̨
local PSEUDOVOWEL = u(0xFFF1) -- pseudovowel placeholder
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder
-- any stress
export.stress = AC .. GR
-- regex for any optional stress(s)
export.opt_stress = "[" .. export.stress .. "]*"
-- any accent
export.accent = export.stress .. DIA .. BREVE .. CARON .. OGONEK
-- regex for any optional accent(s)
export.opt_accent = "[" .. export.accent .. "]*"
-- any composed Cyrillic vowel with grave accent
export.composed_grave_vowel = "ѐЀѝЍ"
-- any Cyrillic vowel except ёЁ
export.vowel_no_jo = "аАеЕиИӥӤіІїЇоОуУыЫѣѢэЭюЮяЯѵѴ" .. PSEUDOVOWEL .. export.composed_grave_vowel
-- any Cyrillic vowel, including ёЁ
export.vowel = export.vowel_no_jo .. "ёЁ"
-- any vowel in transliteration
export.tr_vowel = "aAeEěĚɛƐiIoOǒǑǫǪuUyY" .. PSEUDOVOWEL
-- any consonant in transliteration, omitting "j" and the soft/hard sign
export.tr_cons_no_approx = "bBcCčČdDfFgGkKlLmMnNpPrRsSšŠtTvVxXzZžŽ" .. PSEUDOCONS
-- any consonant in transliteration, including soft/hard sign
export.tr_cons = export.tr_cons_no_approx .. "jJʹʺ"
-- regex for any consonant in transliteration, including soft/hard sign,
-- optionally followed by any accent
export.tr_cons_acc_re = "[" .. export.tr_cons .. "]" .. export.opt_accent
-- any Cyrillic consonant except sibilants and ц
export.cons_except_sib_c = "бБвВгГдДзЗйЙкКлЛмМнНпПрРсСтТфФхХъЪьЬѳѲ" .. PSEUDOCONS
-- Cyrillic sibilant consonants
export.sib = "жЖчЧшШщЩ"
-- Cyrillic sibilant consonants and ц
export.sib_c = export.sib .. "цЦ"
-- any Cyrillic consonant
export.cons = export.cons_except_sib_c .. export.sib_c
-- Cyrillic velar consonants
export.velar = "гГкКхХ"
-- uppercase Cyrillic
export.uppercase = "АБВГДЕЀЁЖЗИЍӤІЇЙКЛМНОПРСТУФХЦЧШЩЪЫЬѢЭЮЯѲѴ"
local function ine(x)
return x ~= "" and x or nil
end
--[==[
Apply Proto-Slavic iotation. This is the change that is affected by a Slavic -j- after a consonant.
`stem` is the Cyrillic stem and `tr` its optional manual translit. If `shch` is given, т iotates to щ instead of ч.
Normally return two values, the iotated Cyrillic stem and corresponding transliteration (which will be {nil} if passed
in as {nil}). If invoked from a template or bot, however, the return value will be a single string; if manual
transliteration is present, the return value will be a string of the form `CYRILLIC//TRANSLIT` with two slahes
separating the Cyrillic from the translit.
]==]
function export.iotation(stem, tr, shch)
local combine_tr = false
-- so this can be called from a template (or usually, a bot)
if type(stem) == "table" then
stem, tr, shch = ine(stem.args[1]), ine(stem.args[2]), ine(stem.args[3])
combine_tr = true
end
stem = ugsub(stem, "[сх]$", "ш")
stem = ugsub(stem, "с[кт]$", "щ")
stem = ugsub(stem, "[кц]$", "ч")
-- normally "т" is iotated as "ч" but there are many verbs that are iotated with "щ"
if shch == "щ" then
stem = stem:gsub("т$", "щ")
else
stem = stem:gsub("т$", "ч")
end
stem = ugsub(stem, "[гдз]$", "ж")
stem = ugsub(stem, "[бвмпфѳ]$", "%0л")
-- ѵ is equivalent to в after certain vowels
stem = ugsub(stem, "[аАеЕѐЀиИѝЍӥӤіІїЇѣѢэЭяЯ]" .. export.opt_stress .. "ѵ$", "%0л")
if tr then
tr = tr:gsub("[sx]$", "š")
:gsub("s[kt]$", "šč")
:gsub("[kc]$", "č")
-- normally "т" is iotated as "ч" but there are many verbs that are iotated with "щ"
if shch == "щ" then
tr = tr:gsub("t$", "šč")
else
tr = tr:gsub("t$", "č")
end
tr = tr:gsub("[dgz]$", "ž")
:gsub("[bfmpv]$", "%0l")
end
if combine_tr then
return export.combine_russian_tr(stem, tr)
end
return stem, tr
end
do
-- A word needs accents if it is unstressed and contains more than one
-- vowel, unless it's a prefix or suffix
local function word_needs_accents(word)
return not (word:sub(1, 1) == "-" or word:sub(-1) == "-") and
export.is_unstressed(word) and not export.is_monosyllabic(word)
end
-- Does a set of Cyrillic words in connected text need accents? We need to
-- split by word and check each one.
function export.needs_accents(text)
for word in gsplit(text, "%s+") do
if word_needs_accents(word) then
return true
end
end
return false
end
end
--[==[
True if either:
# A vowel is marked with explicit primary stress.
# The word has a single jo in it (which doesn't have secondary stress).
This is because a word with multiple jos requires explicit stress to be marked, since we can't infer where primary
stress lies. `Jo` can be `ё`, `ѣ̈`, or `я̈` (e.g. `сѣ̈дла`, plural of `сѣдло́`).
]==]
function export.is_stressed(word)
if word:find(AC) then
return true
end
word = toNFD(word)
return (
select(2, ugsub(word, "[еѣяЕѢЯ]" .. DIA, "")) == 1 and
not umatch(word, "[еѣяЕѢЯ]" .. DIA .. GR)
)
end
--[==[
True if a Cyrillic word requires explicit stress.
]==]
function export.is_unstressed(word)
return not export.is_stressed(word)
end
--[==[
True if Cyrillic word is stressed on the last syllable.
]==]
function export.is_ending_stressed(word)
return ufind(word, "[ёЁ][^" .. export.vowel .. "]*$") or
ufind(word, "[" .. export.vowel .. "][́̈][^" .. export.vowel .. "]*$")
end
do
local function word_is_multi_stressed(word)
-- Allow ё along with another stress, e.g. [[трёхэта́жный]], [[гёрлфре́нд]] or [[Са́мсё]].
return ufind(word, "[" .. export.vowel .. "][́̈].*[" .. export.vowel .. "][́̈]")
end
--[==[
True if a Cyrillic term has two or more stresses (acute or diaeresis) in a given word.
]==]
function export.is_multi_stressed(text)
for word in gsplit(text, "[%s-]+") do
if word_is_multi_stressed(word) then
return true
end
end
return false
end
end
--[==[
True if Cyrillic word is stressed on the first syllable.
]==]
function export.is_beginning_stressed(word)
return ufind(word, "^[^" .. export.vowel .. "]*[ёЁ]") or
ufind(word, "^[^" .. export.vowel .. "]*[" .. export.vowel .. "]́")
end
--[==[
True if Cyrillic word has no vowel. Don't treat suffixes as nonsyllabic even if they have no vowel, as they are
generally added onto words with vowels.
]==]
function export.is_nonsyllabic(word)
return not ufind(word, "^%-") and not ufind(word, "[" .. export.vowel .. "]")
end
--[==[
True if Cyrillic word has no more than one vowel; includes non-syllabic stems such as `льд-`.
]==]
function export.is_monosyllabic(word)
return not ufind(word, "[" .. export.vowel .. "].*[" .. export.vowel .. "]")
end
local recomposer = {
-- Cyrillic letters
["е" .. DIA] = "ё",
["Е" .. DIA] = "Ё",
["и" .. DIA] = "ӥ",
["И" .. DIA] = "Ӥ",
["и" .. BREVE] = "й",
["И" .. BREVE] = "Й",
["і" .. DIA] = "ї",
["І" .. DIA] = "Ї",
-- Latin letters
["c" .. CARON] = "č",
["C" .. CARON] = "Č",
["e" .. CARON] = "ě",
["E" .. CARON] = "Ě",
["o" .. CARON] = "ǒ",
["O" .. CARON] = "Ǒ",
["o" .. OGONEK] = "ǫ",
["O" .. OGONEK] = "Ǫ",
["s" .. CARON] = "š",
["S" .. CARON] = "Š",
["z" .. CARON] = "ž",
["Z" .. CARON] = "Ž",
-- used in ru-pron:
["ж" .. BREVE] = "ӂ", -- used in ru-pron
["Ж" .. BREVE] = "Ӂ",
["j" .. CFLEX] = "ĵ",
["J" .. CFLEX] = "Ĵ",
["j" .. CARON] = "ǰ",
-- no composed uppercase equivalent of J-caron
["ʒ" .. CARON] = "ǯ",
["Ʒ" .. CARON] = "Ǯ",
}
--[==[
Decompose acute, grave, etc. on letters (esp. Latin) into individivual character + combining accent. But recompose
Cyrillic and Latin characters that we want to treat as units and get caught in the crossfire. We mostly want acute and
grave decomposed; perhaps should just explicitly decompose those and no others.
]==]
function export.decompose(text)
return (ugsub(toNFD(text), ".[" .. BREVE .. DIA .. CARON .. OGONEK .. "]", recomposer))
end
function export.assert_decomposed(text)
assert(not ufind(text, "[áéíóúýàèìòùỳäëïöüÿÁÉÍÓÚÝÀÈÌÒÙỲÄËÏÖÜŸ]"))
end
--[==[
Transliterate text and then apply acute/grave decomposition.
]==]
function export.translit(text, no_include_monosyllabic_jo_accent)
local jo_accent = not no_include_monosyllabic_jo_accent and "mono" or nil
return export.decompose(m_ru_translit.tr(text, nil, nil, jo_accent))
end
--[==[
Recompose acutes and graves into preceding vowels. Probably not necessary.
]==]
function export.recompose(text)
return mw.ustring.toNFC(text)
end
local grave_decomposer = {
["ѐ"] = "е" .. GR,
["Ѐ"] = "Е" .. GR,
["ѝ"] = "и" .. GR,
["Ѝ"] = "И" .. GR,
}
--[==[
Decompose precomposed Cyrillic chars w/grave accent; not necessary for acute accent as there aren't precomposed Cyrillic
chars w/acute accent, and undesirable for precomposed `ё` and `Ё`.
]==]
function export.decompose_grave(word)
return (ugsub(word, "[ѐЀѝЍ]", grave_decomposer))
end
local grave_deaccenter = {
[GR] = "", -- grave accent
["ѐ"] = "е", -- composed Cyrillic chars w/grave accent
["Ѐ"] = "Е",
["ѝ"] = "и",
["Ѝ"] = "И",
}
local deaccenter = mw.clone(grave_deaccenter)
deaccenter[AC] = "" -- acute accent
--[==[
Remove acute and grave accents; don't affect composed diaeresis in `ёЁ` or uncomposed diaeresis in `-ѣ̈-` (as in plural
`сѣ̈дла` of `сѣдло́`). NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.remove_accents(word, tr)
local ru_removed = ugsub(word, "[́̀ѐЀѝЍ]", deaccenter)
if not tr then
return ru_removed, nil
end
return ru_removed, (ugsub(tr, "[" .. AC .. GR .. "]", deaccenter))
end
--[==[
Remove grave accents; don't affect acute or composed diaeresis in `ёЁ` or uncomposed diaeresis in `-ѣ̈-` (as in plural
`сѣ̈дла` of `сѣдло́`). NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.remove_grave_accents(word, tr)
local ru_removed = ugsub(word, "[̀ѐЀѝЍ]", grave_deaccenter)
if not tr then
return ru_removed, nil
end
return ru_removed, (ugsub(tr, GR, ""))
end
--[==[
Remove acute and grave accents in monosyllabic words; don't affect diaeresis (composed or uncomposed) because it
indicates a change in vowel quality, which still applies to monosyllabic words. Don't change suffixes, where a
"monosyllabic" stress is still significant (e.g. `-ча́т` short masculine of `-ча́тый`, vs. `-́чат` short masculine of
`-́чатый`). NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.remove_monosyllabic_accents(word, tr)
if export.is_monosyllabic(word) and not ufind(word, "^%-") then
return export.remove_accents(word, tr)
else
return word, tr
end
end
local destresser = mw.clone(deaccenter)
destresser["ё"] = "е"
destresser["Ё"] = "Е"
destresser[DIA] = "" -- diaeresis
-- Subfunction of split_syllables(). On input we get sections of text consisting of CONSONANT - VOWEL - CONSONANT -
-- VOWEL ... - CONSONANT, where CONSONANT consists of zero or more consonants and VOWEL consists of exactly one vowel
-- plus any following accent(s); we combine these into syllables as required by split_syllables().
local function combine_captures(captures)
if captures[1] and not captures[2] then
return captures
end
local combined = {}
for i = 1, (#captures - 1), 2 do
insert(combined, captures[i] .. captures[i+1])
end
combined[#combined] = combined[#combined] .. captures[#captures]
return combined
end
--[==[
Split Russian text and transliteration into syllables. Syllables end with vowel + accent(s), except for the last
syllable, which includes any trailing consonants. NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.split_syllables(ru, tr)
-- Split into alternating consonant/vowel sequences, as described in
-- combine_captures().
local rusyllables = combine_captures(split(ru, "([" .. export.vowel .. "]" .. export.opt_accent .. ")"))
local trsyllables
if tr then
export.assert_decomposed(tr)
trsyllables = combine_captures(split(tr, "([" .. export.tr_vowel .. "]" .. export.opt_accent .. ")"))
if #rusyllables ~= #trsyllables then
error("Russian " .. ru .. " doesn't have same number of syllables as translit " .. tr)
end
end
--error(concat(rusyllables, "/") .. "(" .. #rusyllables .. (trsyllables and (") || " .. concat(trsyllables, "/") .. "(" .. #trsyllables .. ")") or ""))
return rusyllables, trsyllables
end
--[==[
Split Russian word and transliteration into hyphen-separated components. Rejoining with `concat(..., "-")` will
recover the original word. If the original word ends in a hyphen, that hyphen gets included with the preceding component(this is the only case when an individual component has a hyphen in it).
]==]
function export.split_hyphens(ru, tr)
local rucomponents = split(ru, "%-")
if rucomponents[#rucomponents] == "" and #rucomponents > 1 then
rucomponents[#rucomponents - 1] = rucomponents[#rucomponents - 1] .. "-"
table.remove(rucomponents)
end
local trcomponents
if tr then
trcomponents = split(tr, "%-")
if trcomponents[#trcomponents] == "" and #trcomponents > 1 then
trcomponents[#trcomponents - 1] = trcomponents[#trcomponents - 1] .. "-"
table.remove(trcomponents)
end
if #rucomponents ~= #trcomponents then
error("Russian " .. ru .. " doesn't have same number of hyphenated components as translit " .. tr)
end
end
return rucomponents, trcomponents
end
--[==[
Apply `j` correction, converting `je` to `e` after consonants, `jo` to `o` after a sibilant, `ju` to `u` after hard
sibilant. NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.j_correction(tr)
tr = ugsub(tr, "([" .. export.tr_cons_no_approx .. "]" .. export.opt_accent ..")[Jj]([EeĚě])", "%1%2")
tr = ugsub(tr, "([žščŽŠČ])[Jj]([Oo])", "%1%2")
return (ugsub(tr, "([žšŽŠ])[Jj]([Uu])", "%1%2"))
end
local function make_unstressed_ru(ru)
-- The following regexp has grave+acute+diaeresis after the bracket
return (ugsub(ru, "[̀́̈ёЁѐЀѝЍ]", destresser))
end
--[==[
Remove all stress marks (acute, grave, diaeresis). NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.make_unstressed(ru, tr)
-- so this can be called from a template (specifically {{R:ru:Vasmer}})
if type(ru) == "table" then
ru, tr = ine(ru.args[1]), ine(ru.args[2])
end
if not tr then
return make_unstressed_ru(ru), nil
end
-- In the presence of TR, we need to do things the hard way: Splitting
-- into syllables and only converting Latin o to e opposite a ё.
local rusyl, trsyl = export.split_syllables(ru, tr)
for i=1,#rusyl do
if ufind(rusyl[i], "[ёЁ]") then
trsyl[i] = ugsub(trsyl[i], "[Oo]", {["O"] = "E", ["o"] = "e"})
end
rusyl[i] = make_unstressed_ru(rusyl[i])
-- the following should still work as it will affect accents only
trsyl[i] = make_unstressed_ru(trsyl[i])
end
-- Also need to apply j correction as otherwise we'll have je after cons, etc.
return concat(rusyl, ""), export.j_correction(concat(trsyl, ""))
end
local function remove_jo_ru(word)
return (ugsub(word, "[̈ёЁ]", destresser))
end
local function make_unstressed_once_ru(word)
-- leave graves alone
return (ugsub(word, "([́̈ёЁ])([^́̈ёЁ]*)$", function(x, rest) return destresser[x] .. rest; end, 1))
end
--[==[
Remove diaeresis stress marks only. NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.remove_jo(ru, tr)
if not tr then
return remove_jo_ru(ru), nil
end
-- In the presence of TR, we need to do things the hard way: Splitting
-- into syllables and only converting Latin o to e opposite a ё.
local rusyl, trsyl = export.split_syllables(ru, tr)
for i=1,#rusyl do
if ufind(rusyl[i], "[ёЁ]") then
trsyl[i] = ugsub(trsyl[i], "[Oo]", {["O"] = "E", ["o"] = "e"})
end
rusyl[i] = remove_jo_ru(rusyl[i])
-- the following should still work as it will affect accents only
trsyl[i] = make_unstressed_once_ru(trsyl[i])
end
-- Also need to apply j correction as otherwise we'll have je after cons, etc.
return concat(rusyl, ""),
export.j_correction(concat(trsyl, ""))
end
local function map_last_hyphenated_component(fn, ru, tr)
if ufind(ru, "%-") then
-- If there is a hyphen, do it the hard way by splitting into
-- individual components and doing the last one. Otherwise we just do
-- the whole string.
local rucomponents, trcomponents = export.split_hyphens(ru, tr)
local lastru, lasttr = fn(rucomponents[#rucomponents],
trcomponents and trcomponents[#trcomponents] or nil)
rucomponents[#rucomponents] = lastru
ru = concat(rucomponents, "-")
if trcomponents then
trcomponents[#trcomponents] = lasttr
tr = concat(trcomponents, "-")
end
return ru, tr
end
return fn(ru, tr)
end
-- Make last stressed syllable (acute or diaeresis) unstressed; leave unstressed; leave graves alone; if `NOCONCAT`,
-- return individual syllables. NOTE: Translit must already be decomposed! See comment at top.
local function make_unstressed_once_after_hyphen_split(ru, tr, noconcat)
if not tr then
return make_unstressed_once_ru(ru), nil
end
-- In the presence of TR, we need to do things the hard way, as with
-- make_unstressed().
local rusyl, trsyl = export.split_syllables(ru, tr)
for i=#rusyl,1,-1 do
local stressed = export.is_stressed(rusyl[i])
if stressed then
if ufind(rusyl[i], "[ёЁ]") then
trsyl[i] = ugsub(trsyl[i], "[Oo]", {["O"] = "E", ["o"] = "e"})
end
rusyl[i] = make_unstressed_once_ru(rusyl[i])
-- the following should still work as it will affect accents only
trsyl[i] = make_unstressed_once_ru(trsyl[i])
break
end
end
if noconcat then
return rusyl, trsyl
end
-- Also need to apply j correction as otherwise we'll have je after cons
return concat(rusyl, ""),
export.j_correction(concat(trsyl, ""))
end
--[==[
Make last stressed syllable (acute or diaeresis) to the right of any hyphen unstressed (unless the hyphen is
word-final); leave graves alone. We don't destress a syllable to the left of a hyphen unless the hyphen is word-final
(i.e. a prefix). Otherwise e.g. the accents in the first part of words like ко́е-како́й and а́льфа-лу́ч won't remain. NOTE:
Translit must already be decomposed! See comment at top.
]==]
function export.make_unstressed_once(ru, tr)
return map_last_hyphenated_component(make_unstressed_once_after_hyphen_split, ru, tr)
end
local function make_unstressed_once_at_beginning_ru(word)
-- leave graves alone
return (ugsub(word, "^([^́̈ёЁ]*)([́̈ёЁ])", function(rest, x) return rest .. destresser[x]; end, 1))
end
--[==[
Make first stressed syllable (acute or diaeresis) unstressed; leave graves alone; if `NOCONCAT`, return individual
syllables. NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.make_unstressed_once_at_beginning(ru, tr, noconcat)
if not tr then
return make_unstressed_once_at_beginning_ru(ru), nil
end
-- In the presence of TR, we need to do things the hard way, as with
-- make_unstressed().
local rusyl, trsyl = export.split_syllables(ru, tr)
for i=1,#rusyl do
local stressed = export.is_stressed(rusyl[i])
if stressed then
if ufind(rusyl[i], "[ёЁ]") then
trsyl[i] = ugsub(trsyl[i], "[Oo]", {["O"] = "E", ["o"] = "e"})
end
rusyl[i] = make_unstressed_once_at_beginning_ru(rusyl[i])
-- the following should still work as it will affect accents only
trsyl[i] = make_unstressed_once_at_beginning_ru(trsyl[i])
break
end
end
if noconcat then
return rusyl, trsyl
end
-- Also need to apply j correction as otherwise we'll have je after cons
return concat(rusyl, ""),
export.j_correction(concat(trsyl, ""))
end
--[==[
Subfunction of `make_ending_stressed()`, `make_beginning_stressed()`, which add an acute accent to a syllable that may
already have a grave accent; in such a case, remove the grave. NOTE: Translit must already be decomposed! See comment at
top.
]==]
function export.correct_grave_acute_clash(word, tr)
word = ugsub(word, "([̀ѐЀѝЍ])́", function(x) return grave_deaccenter[x] .. AC; end)
word = ugsub(word, AC .. GR, AC)
if not tr then
return word, nil
end
tr = ugsub(tr, GR .. AC, AC)
tr = ugsub(tr, AC .. GR, AC)
return word, tr
end
local function make_ending_stressed_ru(word)
-- If already ending stressed, just return word so we don't mess up ё
if export.is_ending_stressed(word) then
return word
end
-- Destress the last stressed syllable
word = make_unstressed_once_ru(word)
-- Add an acute to the last syllable
word = ugsub(word, "([" .. export.vowel_no_jo .. "])([^" .. export.vowel .. "]*)$",
"%1́%2")
-- If that caused an acute and grave next to each other, remove the grave
return export.correct_grave_acute_clash(word)
end
-- Remove the last primary stress from the word and put it on the final syllable. Leave grave accents alone except in
-- the last syllable. If final syllable already has primary stress, do nothing. NOTE: Translit must already be
-- decomposed! See comment at top.
local function make_ending_stressed_after_hyphen_split(ru, tr)
if not tr then
return make_ending_stressed_ru(ru), nil
end
-- If already ending stressed, just return ru/tr so we don't mess up ё
if export.is_ending_stressed(ru) then
return ru, tr
end
-- Destress the last stressed syllable; pass in "noconcat" so we get
-- the individual syllables back
local rusyl, trsyl = make_unstressed_once_after_hyphen_split(ru, tr, "noconcat")
-- Add an acute to the last syllable of both Russian and translit
rusyl[#rusyl] = ugsub(rusyl[#rusyl], "([" .. export.vowel_no_jo .. "])",
"%1" .. AC)
trsyl[#trsyl] = ugsub(trsyl[#trsyl], "([" .. export.tr_vowel .. "])",
"%1" .. AC)
-- If that caused an acute and grave next to each other, remove the grave
rusyl[#rusyl], trsyl[#trsyl] =
export.correct_grave_acute_clash(rusyl[#rusyl], trsyl[#trsyl])
-- j correction didn't get applied in make_unstressed_once because
-- we short-circuited it and made it return lists of syllables
return concat(rusyl, ""),
export.j_correction(concat(trsyl, ""))
end
--[==[
Remove the last primary stress from the portion of the word to the right of any hyphen (unless the hyphen is word-final)
and put it on the final syllable. Leave grave accents alone except in the last syllable. If final syllable already has
primary stress, do nothing. (See `make_unstressed_once()` for why we don't affect stresses to the left of a hyphen.)
NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.make_ending_stressed(ru, tr)
return map_last_hyphenated_component(make_ending_stressed_after_hyphen_split, ru, tr)
end
local function make_beginning_stressed_ru(word)
-- If already beginning stressed, just return word so we don't mess up ё
if export.is_beginning_stressed(word) then
return word
end
-- Destress the first stressed syllable
word = make_unstressed_once_at_beginning_ru(word)
-- Add an acute to the first syllable
word = ugsub(word, "^([^" .. export.vowel .. "]*)([" .. export.vowel_no_jo .. "])",
"%1%2́")
-- If that caused an acute and grave next to each other, remove the grave
return export.correct_grave_acute_clash(word)
end
--[==[
Remove the first primary stress from the word and put it on the initial syllable. Leave grave accents alone except in
the first syllable. If initial syllable already has primary stress, do nothing. NOTE: Translit must already be
decomposed! See comment at top.
]==]
function export.make_beginning_stressed(ru, tr)
if not tr then
return make_beginning_stressed_ru(ru), nil
end
-- If already beginning stressed, just return ru/tr so we don't mess up ё
if export.is_beginning_stressed(ru) then
return ru, tr
end
-- Destress the first stressed syllable; pass in "noconcat" so we get
-- the individual syllables back
local rusyl, trsyl = export.make_unstressed_once_at_beginning(ru, tr, "noconcat")
-- Add an acute to the first syllable of both Russian and translit
rusyl[1] = ugsub(rusyl[1], "([" .. export.vowel_no_jo .. "])",
"%1" .. AC)
trsyl[1] = ugsub(trsyl[1], "([" .. export.tr_vowel .. "])",
"%1" .. AC)
-- If that caused an acute and grave next to each other, remove the grave
rusyl[1], trsyl[1] = export.correct_grave_acute_clash(rusyl[1], trsyl[1])
-- j correction didn't get applied in make_unstressed_once_at_beginning
-- because we short-circuited it and made it return lists of syllables
return concat(rusyl, ""),
export.j_correction(concat(trsyl, ""))
end
-- used for tracking and categorization
local hard_cons = {"hard-cons", "cons"}
local hard_vowel = {"vowel", "hard-vowel"}
local i_vowel = {"i", "vowel", "soft-vowel"}
local sibilant_cons = {"sibilant", "cons"}
local soft_vowel = {"vowel", "soft-vowel"}
local velar_cons = {"velar", "cons"}
local trailing_letter_type = {
["ш"] = sibilant_cons,
["щ"] = sibilant_cons,
["ч"] = sibilant_cons,
["ж"] = sibilant_cons,
["ц"] = {"c", "cons"},
["к"] = velar_cons,
["г"] = velar_cons,
["х"] = velar_cons,
["ь"] = {"soft-cons", "cons"},
["ъ"] = hard_cons,
["й"] = {"palatal", "cons"},
["а"] = hard_vowel,
["я"] = soft_vowel,
["э"] = hard_vowel,
["е"] = soft_vowel,
["ѐ"] = soft_vowel,
["ѣ"] = soft_vowel,
["и"] = i_vowel,
["ѝ"] = i_vowel,
["ӥ"] = i_vowel,
["і"] = i_vowel,
["ї"] = i_vowel,
["ѵ"] = i_vowel,
["ы"] = hard_vowel,
["о"] = hard_vowel,
["ё"] = soft_vowel,
["у"] = hard_vowel,
["ю"] = soft_vowel,
}
function export.get_stem_trailing_letter_type(stem)
return trailing_letter_type[ulower(usub(export.remove_accents(stem), -1))] or hard_cons
end
--[==[
Reduce stem by eliminating the "epenthetic" vowel. Applies to nominative singular masculine 2nd-declension hard and
soft, and 3rd-declension feminine in -ь (e.g. [[любовь]]). `STEM` should be the result after calling
`detect_stem_type()`, but with final -й if present. Normally returns two arguments (`STEM` and `TR`), but can be called
from a template or bot using `#invoke` and will return one argument (`STEM`, or `STEM//TR` if `TR` is present). Returns
{nil} if unable to reduce. NOTE: Translit must already be decomposed! See comment at top.
]==]
function export.reduce_stem(stem, tr, soft_n)
local pre, letter, post
local pretr, lettertr, posttr
local combine_tr = false
-- test cases with translit:
-- =p.reduce_stem("фе́ез", "fɛ́jez") -> фе́йз, fɛ́jz
-- =p.reduce_stem("фе́йез", "fɛ́jez") -> фе́йз, fɛ́jz
-- =p.reduce_stem("фе́без", "fɛ́bez") -> фе́бз, fɛ́bz
-- =p.reduce_stem("фе́лез", "fɛ́lez") -> фе́льз, fɛ́lʹz
-- =p.reduce_stem("феёз", p.decompose("fɛjóz")) -> фейз, fɛjz
-- =p.reduce_stem("фейёз", p.decompose("fɛjjóz")) -> фейз, fɛjz
-- =p.reduce_stem("фебёз", p.decompose("fɛbjóz")) -> фебз, fɛbz
-- =p.reduce_stem("фелёз", p.decompose("fɛljóz")) -> фельз, fɛlʹz
-- =p.reduce_stem("фе́бей", "fɛ́bej") -> фе́бь, fɛ́bʹ
-- =p.reduce_stem("фебёй", p.decompose("fɛbjój")) -> фебь, fɛbʹ
-- =p.reduce_stem("фе́ей", "fɛ́jej") -> фе́йй, fɛ́jj
-- =p.reduce_stem("феёй", p.decompose("fɛjój")) -> фейй, fɛjj
-- so this can be called from a template (or usually, a bot)
if type(stem) == "table" then
stem, tr = ine(stem.args[1]), ine(stem.args[2])
combine_tr = true
end
pre, letter, post = umatch(stem, "^(.*)([оОеЕёЁ])́?([" .. export.cons .. "]+)$")
if not pre then
return nil, nil
end
if tr then
-- FIXME, may not be necessary to write the posttr portion as a
-- consonant + zero or more consonant/accent combinations -- when will
-- we ever get an accent after a consonant? That would indicate a
-- failure of the decompose mechanism.
pretr, lettertr, posttr = umatch(tr, "^(.*)([oOeE])́?([" .. export.tr_cons .. "][" .. export.tr_cons .. export.accent .. "]*)$")
if not pretr then
return nil, nil -- should not happen unless tr is really messed up
end
-- Remove any trailing j's on the translit stem which don't have a
-- corresponding й on the Cyrillic stem. This avoids excess j's with
-- cases like индонези́ец//indonɛzíjec, but retains multiple j's where
-- necessary.
pretr = ugsub(pretr, "[jJ]+$", function(m)
return usub(m, 1, ulen(umatch(pre, "[йЙ]*$")))
end)
end
if letter == "О" or letter == "о" then
-- FIXME, what about when the accent is on the removed letter?
if post == "й" or post == "Й" then
-- FIXME, is this correct?
return nil, nil
end
letter = ""
else
local is_upper = ufind(post, "[" .. export.uppercase .. "]")
if ufind(pre, "[" .. export.vowel .. "]́?$") then
letter = is_upper and "Й" or "й"
elseif post == "й" or post == "Й" then
letter = is_upper and "Ь" or "ь"
post = ""
if posttr then
posttr = ""
end
elseif ufind(post, "[" .. export.velar .. "]$") and ufind(pre, "[" .. export.cons_except_sib_c .. "]$") or
ufind(post, "[^йЙ" .. export.velar .. "]$") and ufind(pre, "[лЛ]$") or
soft_n and ufind(pre, "[нН]$") then
letter = is_upper and "Ь" or "ь"
else
letter = ""
end
end
stem = pre .. letter .. post
if tr then
tr = pretr .. export.translit(letter) .. posttr
end
if combine_tr then
return export.combine_russian_tr(stem, tr)
else
return stem, tr
end
end
--[==[
Generate the dereduced stem given `STEM` and `EPENTHETIC_STRESS` (which indicates whether the epenthetic vowel should be
stressed); this is without any terminating non-syllabic ending, which is added if needed by the calling function.
Normally returns two arguments (`STEM` and `TR`), but can be called from a template using `#invoke` (or by bot) and will
return one argument (`STEM`, or `STEM//TR` if `TR` is present). Returns {nil} if unable to dereduce. NOTE: Translit
must already be decomposed! See comment at top.
]==]
function export.dereduce_stem(stem, tr, epenthetic_stress)
local combine_tr = false
-- so this can be called from a template (or usually, a bot)
if type(stem) == "table" then
stem, tr, epenthetic_stress = ine(stem.args[1]), ine(stem.args[2]), ine(stem.args[3])
combine_tr = true
end
if epenthetic_stress then
stem, tr = export.make_unstressed_once(stem, tr)
end
local pre, letter, post
local pretr, lettertr, posttr
-- FIXME!!! Deal with this special case
--if not (z.stem_type == "soft" and _.equals(z.stress_type, {"b", "f"}) -- we should ignore asterix for 2*b and 2*f (so to process it just like 2b or 2f)
-- or _.contains(z.specific, "(2)") and _.equals(z.stem_type, {"velar", "letter-ц", "vowel"})) -- and also the same for (2)-specific and 3,5,6 stem-types
--then
-- I think this corresponds to our -ья and -ье types, which we
-- handle separately
--if z.stem_type == "vowel" then -- 1).
-- if _.equals(z.stress_type, {"b", "c", "e", "f", "f'", "b'" }) then -- gen_pl ending stressed -- TODO: special vars for that
-- z.stems["gen_pl"] = _.replace(z.stems["gen_pl"], "ь$", "е́")
-- else
-- z.stems["gen_pl"] = _.replace(z.stems["gen_pl"], "ь$", "и")
-- end
--end
pre, letter, post = umatch(stem, "^(.*)([" .. export.cons .. "])([" .. export.cons .. "])$")
if tr then
pretr, lettertr, posttr = umatch(tr, "^(.*)(" .. export.tr_cons_acc_re .. ")(" .. export.tr_cons_acc_re .. ")$")
if pre and not pretr then
return nil, nil -- should not happen unless tr is really messed up
end
end
if pre then
local is_upper = ufind(post, "[" .. export.uppercase .. "]")
local epvowel
if ufind(letter, "[ьйЬЙ]") then
letter = ""
lettertr = ""
if ufind(post, "[цЦ]$") or not epenthetic_stress then
epvowel = is_upper and "Е" or "е"
else
epvowel = is_upper and "Ё" or "ё"
end
elseif ufind(letter, "[" .. export.cons_except_sib_c .. "]") and ufind(post, "[" .. export.velar .. "]") or
ufind(letter, "[" .. export.velar .. "]") then
epvowel = is_upper and "О" or "о"
elseif post == "ц" or post == "Ц" then
epvowel = is_upper and "Е" or "е"
elseif epenthetic_stress then
if ufind(letter, "[" .. export.sib .. "]") then
epvowel = is_upper and "О́" or "о́"
else
epvowel = is_upper and "Ё" or "ё"
end
else
epvowel = is_upper and "Е" or "е"
end
assert(epvowel)
stem = pre .. letter .. epvowel .. post
if tr then
tr = pretr .. lettertr .. export.translit(epvowel) .. posttr
tr = export.j_correction(tr)
end
if epenthetic_stress then
stem, tr = export.make_ending_stressed(stem, tr)
end
if combine_tr then
return export.combine_russian_tr(stem, tr)
else
return stem, tr
end
end
return nil, nil
end
--[==[
Parse an entry that potentially has final footnote symbols and initial `*` for a hypothetical entry into initial
symbols, text and final symbols.
]==]
function export.split_symbols(entry, do_subscript)
local prefentry, finalnotes = m_table_tools.separate_notes(entry)
local initnotes, text = umatch(prefentry, "(%*?)(.*)$")
return initnotes, text, finalnotes
end
--------------------------------------------------------------------------
-- Used for manual translit --
--------------------------------------------------------------------------
--[==[
Transliterate text after removing any links. The translit is decomposed in the process.
]==]
function export.translit_no_links(text)
return export.translit(require("Module:links").remove_links(text))
end
--[==[
Split a combined Cyrillic/translit string (either in the form `CYRILLIC//TRANSLIT` or just `CYRILLIC`) into its
components, decompose the translit, and either return a two-element list of `CYRILLIC` and `TRANSLIT` (if `dopair` is
given), or two separate return values (if `dopair` is not specified).
]==]
function export.split_russian_tr(term, dopair)
local ru, tr
if not term:find("//") then
ru = term
else
local splitvals = split(term, "//")
if #splitvals ~= 2 then
error("Must have at most one // in a Russian//translit expr: '" .. term .. "'")
end
ru, tr = splitvals[1], export.decompose(splitvals[2])
end
if dopair then
return {ru, tr}
else
return ru, tr
end
end
--[==[
Combine Cyrillic and translit into a single string separated by `//`. If translit is {nil}, the return value will be
the same as the passed-in Cyrillic. `ru` can be a string (which any manual translit in `tr`) or a two-element table of
`{CYRILLIC, TRANSLIT}`.
]==]
function export.combine_russian_tr(ru, tr)
if type(ru) == "table" then
ru, tr = unpack(ru)
end
if tr then
return ru .. "//" .. tr
else
return ru
end
end
local function concat_maybe_moving_notes(x, y, movenotes)
if movenotes then
local xentry, xnotes = m_table_tools.separate_notes(x)
local yentry, ynotes = m_table_tools.separate_notes(y)
return xentry .. yentry .. xnotes .. ynotes
else
return x .. y
end
end
--[==[
Concatenate two Cyrillic strings `RU1` and `RU2` that may have corresponding manual transliteration `TR1` and `TR2`
(which should be {nil} if there is no manual translit, and otherwise should be decomposed). If `DOPAIR`, return a
two-item list of the combined Cyrillic and manual translit (which will be {nil} if both `TR1` and `TR2` are {nil});
else, return two values, the combined Cyrillic and manual translit. If `MOVENOTES`, extract any footnote symbols at the
end of `RU1` and move them to the end of the concatenated string, before any footnote symbols for `RU2`; same thing goes
for `TR1` and `TR2`.
]==]
function export.concat_russian_tr(ru1, tr1, ru2, tr2, dopair, movenotes)
local ru, tr
if not tr1 and not tr2 then
ru = concat_maybe_moving_notes(ru1, ru2, movenotes)
else
if not tr1 then
tr1 = export.translit_no_links(ru1)
end
if not tr2 then
tr2 = export.translit_no_links(ru2)
end
ru, tr = concat_maybe_moving_notes(ru1, ru2, movenotes), export.j_correction(concat_maybe_moving_notes(tr1, tr2, movenotes))
end
if dopair then
return {ru, tr}
else
return ru, tr
end
end
--[==[
Concatenate two Cyrillic/translit combinations (where each combination is a two-element list of `{CYRILLIC, TRANSLIT}`
where `TRANSLIT` may be nil) by individually concatenating the Cyrillic and translit portions, and return a concatenated
combination as a two-element list. If the manual translit portions of both terms on entry are {nil}, the result will
also have {nil} manual translit. If `MOVENOTES`, extract any footnote symbols at the end of `TERM1` and move them after
the concatenated string and before any footnote symbols at the end of `TERM2`.
]==]
function export.concat_paired_russian_tr(term1, term2, movenotes)
assert(type(term1) == "table")
assert(type(term2) == "table")
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
return export.concat_russian_tr(ru1, tr1, ru2, tr2, "dopair", movenotes)
end
function export.concat_forms(forms)
local joined_rutr = {}
for _, form in ipairs(forms) do
insert(joined_rutr, export.combine_russian_tr(form))
end
return concat(joined_rutr, ",")
end
--[==[
Given a list of forms, where each form is a two-element list of `{CYRILLIC, TRANSLIT}`, strip footnote symbols from the
end of the Cyrillic and translit.
]==]
function export.strip_notes_from_forms(forms)
local newforms = {}
for _, form in ipairs(forms) do
local ru, tr = form[1], form[2]
ru, _ = m_table_tools.separate_notes(ru)
if tr then
tr, _ = m_table_tools.separate_notes(tr)
end
insert(newforms, {ru, tr})
end
return newforms
end
--[==[
Given a list of forms, where each form is a two-element list of `{CYRILLIC, TRANSLIT}`, unzip into parallel lists of
Cyrillic and translit. The latter list may have gaps in it.
]==]
function export.unzip_forms(forms)
local rulist = {}
local trlist = {}
for i, form in ipairs(forms) do
local ru, tr = form[1], form[2]
rulist[i] = ru
trlist[i] = tr
end
return rulist, trlist
end
--[==[
Given parallel lists of Cyrillic and translit (where the latter list may have gaps in it), return a list of forms,
where each form is a two-element list of `{CYRILLIC, TRANSLIT}`.
]==]
function export.zip_forms(rulist, trlist)
local forms = {}
for i, ru in ipairs(rulist) do
insert(forms, {ru, trlist[i]})
end
return forms
end
local function any_forms_have_translit(forms)
for _, form in ipairs(forms) do
if form[2] then
return true
end
end
return false
end
--[==[
Given a list of forms, where each form is a two-element list of `{CYRILLIC, TRANSLIT}`, combine forms with identical
Cyrillic, concatenating the translit with a comma+space in between.
]==]
function export.combine_translit_of_duplicate_forms(forms)
if not forms[1] then
return forms
end
-- Optimization to avoid creating a new list in the majority case when no translit exists.
if not any_forms_have_translit(forms) then
return forms
end
local newforms = {}
insert(newforms, {forms[1][1], forms[1][2]})
for i = 2, #forms do
local found_duplicate = false
for j = 1, #newforms do
-- If the Russian of the next form is the same as that of the last one, combine their translits and modify
-- newforms[] in-place. Otherwise add the next form to newforms[]. Make sure to clone the form rather than
-- just appending it directly since we may modify it in-place; we don't want to side-effect `forms` as
-- passed in.
if forms[i][1] == newforms[j][1] then
local tr1 = newforms[j][2]
local tr2 = forms[i][2]
if not tr1 and not tr2 then
-- this shouldn't normally happen
else
tr1 = tr1 or export.translit_no_links(newforms[j][1])
tr2 = tr2 or export.translit_no_links(forms[i][1])
if tr1 == tr2 then
-- this shouldn't normally happen
else
newforms[j][2] = tr1 .. ", " .. tr2
end
end
found_duplicate = true
break
end
end
if not found_duplicate then
insert(newforms, {forms[i][1], forms[i][2]})
end
end
return newforms
end
function export.any_termobjs_have_translit(termobjs)
for _, termobj in ipairs(termobjs) do
if termobj.tr then
return true
end
end
return false
end
--[==[
Given a list of term objects, where each object is a table of `{term = CYRILLIC, tr = TRANSLIT, ...}`, combine forms
with identical Cyrillic and identical ancillary properties, concatenating the translit with a comma+space in between.
Also recompose all transliteration.
]==]
function export.combine_translit_of_duplicate_termobjs_and_recompose(termobjs)
if not termobjs[1] then
return termobjs
end
-- Optimization to avoid creating a new list in the majority case when no translit exists.
if not export.any_termobjs_have_translit(termobjs) then
return termobjs
end
local newtermobjs = {}
insert(newtermobjs, m_table.shallowCopy(termobjs[1]))
for i = 2, #termobjs do
local found_duplicate = false
for j = 1, #newtermobjs do
-- If the Russian of the next termobj is the same as that of the last one, combine their translits and
-- modify newtermobjs[] in-place. Otherwise add the next termobj to newtermobjs[]. Make sure to clone the
-- termobj rather than just appending it directly since we may modify it in-place; we don't want to
-- side-effect `termobjs` as passed in.
if termobjs[i].term == newtermobjs[j].term and
m_headword_utilities.termobj_ancillary_properties_equal(termobjs[i], newtermobjs[j]) then
local tr1 = newtermobjs[j].tr
local tr2 = termobjs[i].tr
if not tr1 and not tr2 then
-- this shouldn't normally happen
else
tr1 = tr1 or export.translit_no_links(newtermobjs[j].term)
tr2 = tr2 or export.translit_no_links(termobjs[i].term)
if tr1 == tr2 then
-- this shouldn't normally happen
else
newtermobjs[j].tr = tr1 .. ", " .. tr2
end
end
found_duplicate = true
break
end
end
if not found_duplicate then
insert(newtermobjs, m_table.shallowCopy(termobjs[i]))
end
end
for _, newtermobj in ipairs(newtermobjs) do
if newtermobj.tr then
newtermobj.tr = export.recompose(newtermobj.tr)
end
end
return newtermobjs
end
--[==[
Given a list of forms, where each form is a two-element list of `{CYRILLIC, TRANSLIT}`, split cases where two different
transliterations have been packed into a single translit field by creating two adjacent term/translit pairs. This is
the opposite operation of `combine_translit_of_duplicate_forms()`.
]==]
function export.split_translit_of_duplicate_forms(forms)
if not forms[1] then
return forms
end
-- Optimization to avoid creating a new list in the majority case when no translit exists.
if not export.any_forms_have_translit(forms) then
return forms
end
local newforms = {}
for _, form in ipairs(forms) do
local ru, tr = unpack(form)
if not tr or not tr:find(",") or ru:find(",") then
insert(newforms, form)
else
local split_trs = split(tr, ",%s*")
local default_tr = export.translit_no_links(ru)
for _, split_tr in ipairs(split_trs) do
if split_tr == default_tr then
split_tr = nil
end
insert(newforms, {ru, split_tr})
end
end
end
return newforms
end
--[==[
Given a list of forms, where each form is a two-element list of `{CYRILLIC, TRANSLIT}`, split cases where two different
transliterations have been packed into a single translit field by creating two adjacent term/translit pairs. This is
the opposite operation of `combine_translit_of_duplicate_forms()`.
]==]
function export.split_translit_of_duplicate_termobjs_and_decompose(termobjs)
if not termobjs[1] then
return termobjs
end
-- Optimization to avoid creating a new list in the majority case when no translit exists.
if not export.any_termobjs_have_translit(termobjs) then
return termobjs
end
local newobjs = {}
for _, obj in ipairs(termobjs) do
local tr = obj.tr
if tr then
tr = export.decompose(tr)
end
if not tr or not tr:find(",") or obj.term:find(",[^%s]") then
if not tr or tr == obj.tr then
insert(newobjs, obj)
else
obj = m_table.shallowCopy(obj)
obj.tr = tr
insert(newobjs, obj)
end
else
local term = obj.term
local embedded_comma_in_term = not not term:find(",")
-- If there's an embedded comma in the term, we want to split on commas not followed by a space; otherwise,
-- we split on commas whether or not followed by a space. To implement "comma not followed by space", we
-- can use a "frontier pattern"; the one below matches if the character after the comma is in the specified
-- set (which is anything but a comma or space) and the comma itself is not in the specified set (in other
-- words, it is a comma or space, which matches because it's a comma). This doesn't work correctly if there
-- are two commas in a row, but that should not happen as there should not be an empty translit.
local split_trs = split(tr, embedded_comma_in_term and ",%f[^,%s]" or ",%s*")
local default_tr = export.translit_no_links(term)
for _, split_tr in ipairs(split_trs) do
if split_tr == default_tr then
split_tr = nil
end
local newobj = m_table.shallowCopy(obj)
newobj.tr = split_tr
insert(newobjs, newobj)
end
end
end
return newobjs
end
function export.strip_ending(ru, tr, ending)
local strippedru = ugsub(ru, ending .. "$", "")
if strippedru == ru then
error("Argument " .. ru .. " doesn't end with expected ending " .. ending)
end
ru = strippedru
tr = export.strip_tr_ending(tr, ending)
return ru, tr
end
function export.strip_tr_ending(tr, ending)
if not tr then return nil end
local endingtr = ugsub(export.translit_no_links(ending), "^([Jj])", "%1?")
local strippedtr = ugsub(tr, endingtr .. "$", "")
if strippedtr == tr then
error("Translit " .. tr .. " doesn't end with expected ending " .. endingtr)
end
return strippedtr
end
return export
jifqt1url7tz4h3rtigfh31hoqhxgrp
အဆက်လက္ကရဴ:ယူနဳကုဒ်/အက္ခရ်လပ်တေန်သၠဲပတိတ်အခိၚ်-ဃ
100
11977
399754
184410
2026-07-20T14:27:23Z
咽頭べさ
33
399754
wikitext
text/x-wiki
{{Unicode character list header}}
{{Unicode character list}}
ttzawwpka9qk1qjw50j3ep2eaqycaqw
злоба
0
24222
399788
34341
2026-07-21T01:40:07Z
咽頭べさ
33
399788
wikitext
text/x-wiki
==ဗူလ်ဂရဳယာန်==
===နိရုတ်===
{{inh+|bg|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{bg-pr|зло́ба}}
===နာမ်===
{{bg-noun|зло́ба|f}}
# စိုတ်ပစ္ဆရိယ၊ စိုတ်ဟွံဒး၊ စိုတ်ဆန္ဒလ္ပာ်ပရေံ၊ ဟွံဒးစိုတ်ညးတၞဟ်ခိုဟ်စ။
# ဂမ္တၚ်၊ ပရေၚ်ဒှ်ဒေါသ၊ ဂမျိ၊ ပရေၚ်မဂၠာဲသၞ။
====လဟုတ်စှ်ေ====
{{bg-ndecl|зло́ба<>}}
==မက်သဳဒဝ်နဳယျာ==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|mk|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{mk-IPA}}
===နာမ်===
{{mk-noun|f|adj=злобен}}
# မယုတ်မာ၊ စိုတ်ပစ္ဆရိယ၊ ပရေၚ်ဒှ်မယုတ်မာကြံကြ။
# ပူဂဵုမယုတ်မာကြံကြ။
# စိုတ်ဂၞံၚ်ဂၞာတ်။
====လဟုတ်စှ်ေ====
{{mk-decl-noun-f|злоб}}
==ရုဿျှာ==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|ru|orv|зълоба}}၊ နူကဵုဝေါဟာ {{inh|ru|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́ба}}
* {{audio|ru|Ru-злоба.ogg}}
===နာမ်===
{{ru-noun+|зло́ба}}
# ဂမ္တၚ်။
# စိုတ်ဟွံဒး၊ စိုတ်ပစ္ဆရိယ။
# ပရေၚ်မနောဒေါသတိတ်၊ ဒေါသ။
# စိုတ်ဂၞံၚ်ဂၞာတ်။
====လဟုတ်စှ်ေ====
{{ru-noun-table|зло́ба}}
{{ru-noun-table|зло́ба|old=1}}
==သာဗ်ခြဝ်ဨရှဳယာန်==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|sh|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{sh-IPA|zlòba}}
* {{hyphenation|sh|зло|ба}}
===နာမ်===
{{sh-noun|зло̀ба|f}}
# စိုတ်ပစ္ဆရိယ၊ မဂၠာဲသၞ။
====လဟုတ်စှ်ေ====
{{sh-decl-noun-unc
|злоба
|злобе
|злоби
|злобу
|злобо
|злоби
|злобом
}}
==ယူကရိန်==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|uk|orv|зълоба}}၊ နူကဵုဝေါဟာ {{inh|uk|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{uk-IPA|зло́ба|ann=y}}
* {{uk-IPA|злоба́|ann=y}}
{{rfap|uk}}
===နာမ်===
{{uk-noun|((зло́ба<sg>,злоба́<sg>))}}
# စိုတ်ပစ္ဆရိယ၊ မၞုံကဵုစိုတ်ညးတၞဟ်ခိုဟ်စဟွံဒးစိုတ်၊ စိုတ်ဟွံဒး၊ အာဃာတ။
#: {{syn|uk|злість|g1=f|зло|g2=n|злопа́м'ятність|g3=f|гнів|g4=m|лють|g5=f|розлю́ченість|g6=f}}
====လဟုတ်စှ်ေ====
{{uk-ndecl|((зло́ба<sg>,злоба́<sg>))}}
dgp8tedf3peahuhhk9jen8j5u7knu0s
399814
399788
2026-07-21T06:08:01Z
咽頭べさ
33
399814
wikitext
text/x-wiki
==ဗူလ်ဂရဳယာန်==
===နိရုတ်===
{{inh+|bg|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{bg-pr|зло́ба}}
===နာမ်===
{{bg-noun|зло́ба|f}}
# စိုတ်ပစ္ဆရိယ၊ စိုတ်ဟွံဒး၊ စိုတ်ဆန္ဒလ္ပာ်ပရေံ၊ ဟွံဒးစိုတ်ညးတၞဟ်ခိုဟ်စ။
# ဂမ္တၚ်၊ ပရေၚ်ဒှ်ဒေါသ၊ ဂမျိ၊ ပရေၚ်မဂၠာဲသၞ။
====လဟုတ်စှ်ေ====
{{bg-ndecl|зло́ба<>}}
==မက်သဳဒဝ်နဳယျာ==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|mk|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{mk-IPA}}
===နာမ်===
{{mk-noun|f|adj=злобен}}
# မယုတ်မာ၊ စိုတ်ပစ္ဆရိယ၊ ပရေၚ်ဒှ်မယုတ်မာကြံကြ။
# ပူဂဵုမယုတ်မာကြံကြ။
# စိုတ်ဂၞံၚ်ဂၞာတ်။
====လဟုတ်စှ်ေ====
{{mk-decl-noun-f|злоб}}
==ရုဿျှာ==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၁}}
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|ru|orv|зълоба}}၊ နူကဵုဝေါဟာ {{inh|ru|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́ба}}
* {{audio|ru|Ru-злоба.ogg}}
===နာမ်===
{{ru-noun+|зло́ба}}
# ဂမ္တၚ်။
# စိုတ်ဟွံဒး၊ စိုတ်ပစ္ဆရိယ။
# ပရေၚ်မနောဒေါသတိတ်၊ ဒေါသ။
# စိုတ်ဂၞံၚ်ဂၞာတ်။
====လဟုတ်စှ်ေ====
{{ru-noun-table|зло́ба}}
{{ru-noun-table|зло́ба|old=1}}
==သာဗ်ခြဝ်ဨရှဳယာန်==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|sh|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{sh-IPA|zlòba}}
* {{hyphenation|sh|зло|ба}}
===နာမ်===
{{sh-noun|зло̀ба|f}}
# စိုတ်ပစ္ဆရိယ၊ မဂၠာဲသၞ။
====လဟုတ်စှ်ေ====
{{sh-decl-noun-unc
|злоба
|злобе
|злоби
|злобу
|злобо
|злоби
|злобом
}}
==ယူကရိန်==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|uk|orv|зълоба}}၊ နူကဵုဝေါဟာ {{inh|uk|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{uk-IPA|зло́ба|ann=y}}
* {{uk-IPA|злоба́|ann=y}}
===နာမ်===
{{uk-noun|((зло́ба<sg>,злоба́<sg>))}}
# စိုတ်ပစ္ဆရိယ၊ မၞုံကဵုစိုတ်ညးတၞဟ်ခိုဟ်စဟွံဒးစိုတ်၊ စိုတ်ဟွံဒး၊ အာဃာတ။
#: {{syn|uk|злість|g1=f|зло|g2=n|злопа́м'ятність|g3=f|гнів|g4=m|лють|g5=f|розлю́ченість|g6=f}}
====လဟုတ်စှ်ေ====
{{uk-ndecl|((зло́ба<sg>,злоба́<sg>))}}
kxsre6qrlcj70bxwwp5eq6n6ftjds9e
မဝ်ဂျူ:ru-headword
828
24230
399854
272761
2026-07-22T23:37:07Z
咽頭べさ
33
399854
Scribunto
text/plain
--[=[
This module implements the headword templates {{ru-noun}}, {{ru-adj}}, {{ru-adv}}, {{ru-noun+}}, etc. The main entry
point is show(), which is meant to be called from one of the above templates. However, {{ru-noun+}} uses the entry
point noun_plus(). When calling show(), the first parameter of the #invoke call is the part of speech. Other
parameters are taken from the parent template call.
The implementations for different types of headwords (different parts of speech) are set in pos_functions[POS] for a
given POS (part of speech).
]=]--
local export = {}
local force_cat = false -- for testing; if true, categories appear in non-mainspace pages
local lang = require("Module:languages").getByCode("ru")
local langname = lang:getCanonicalName()
local com = require("Module:ru-common")
local m_links = require("Module:links")
local m_table_tools = require("Module:table tools")
local require_when_needed = require("Module:require when needed")
local en_utilities_module = "Module:en-utilities"
local json_module = "Module:JSON"
local headword_module = "Module:headword"
local headword_utilities_module = "Module:headword utilities"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local m_en_utilities = require_when_needed(en_utilities_module)
local m_headword_utilities = require_when_needed(headword_utilities_module)
local m_string_utilities = require_when_needed(string_utilities_module)
local m_table = require_when_needed(table_module)
local glossary_link = require_when_needed(headword_utilities_module, "glossary_link")
local shallowCopy = require_when_needed(table_module, "shallowCopy")
local insertIfNot = require_when_needed(table_module, "insertIfNot")
local boolean_param = {type = "boolean"}
local list_param = {list = true, disallow_holes = true}
local list_comp = {list = "comp", disallow_holes = true}
local list_sup = {list = "sup", disallow_holes = true}
local u = m_string_utilities.char
local rfind = m_string_utilities.find
local rsubn = m_string_utilities.gsub
local rmatch = m_string_utilities.match
local rsplit = m_string_utilities.split
local concat = table.concat
local insert = table.insert
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
-- Forward references
local do_noun
local AC = u(0x0301) -- acute = ́
local pos_functions = {}
-- 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
local function track(page)
require("Module:debug/track")("ru-headword/" .. page)
return true
end
-- Clone args while also assigning nil to empty strings.
local function clone_args(in_args)
local args = {}
for pname, param in pairs(in_args) do
if param == "" then args[pname] = nil
else args[pname] = param
end
end
return args
end
local function make_qualifier_text(text)
return require("Module:qualifier").format_qualifier(text)
end
-- Split a list of "RUSSIAN" or "RUSSIAN//TRANSLIT" strings into a list of {RUSSIAN, TRANSLIT} objects.
local function split_list_into_russian_tr(list)
local splitlist = {}
for _, item in ipairs(list) do
insert(splitlist, com.split_russian_tr(item, "dopair"))
end
return splitlist
end
local function check_if_accent_needed(termobj, data, is_head)
local val = termobj.term
local val_no_links = m_links.remove_links(val)
if com.needs_accents(val_no_links) then
if not termobj.unknown_stress and not termobj.nostress then
error("Stress must be supplied using an acute accent or ё: '" .. val_no_links .. "' (use inline modifier <unknown_stress:1> if stress is unknown and <nostress:1> if a multisyllable word really has no stress, as in ''до́ смерти'')")
end
if not termobj.nostress then
local pos = require(en_utilities_module).singularize(data.pos_category)
-- insert(data.categories, "Requests for accents in " .. langname .. " " .. pos .. " entries")
end
end
if com.is_multi_stressed(val_no_links) then
error("Multi-stressed form '" .. val_no_links .. "' not allowed")
end
end
-- Parse the forms of an inflection. The raw arguments are specified in `forms`, a list of forms which are parsed for
-- inline modifiers. Multiple comma-separated values are allowed.
local function parse_inflection_forms(data, forms, field, is_head)
local retobjs = m_headword_utilities.parse_term_list_with_modifiers {
forms = forms,
paramname = field,
splitchar = ",",
is_head = is_head,
include_mods = {
"tr",
{"nostress", {type = "boolean"}},
{"unknown_stress", {type = "boolean"}},
},
}
for _, retobj in ipairs(retobjs) do
if is_head and retobj.term == "+" then
retobj.term = data.pagename
end
check_if_accent_needed(retobj, data, is_head)
if is_head then
-- Catch errors in arguments where headword doesn't match page title; for the moment, do only with
-- tracking.
local head_no_links = m_links.remove_links(retobj.term)
local head_noaccent = com.remove_accents(head_no_links)
if head_noaccent ~= data.pagename then
track("bad-headword")
--error("Headword " .. term .. " doesn't match pagename " .. data.pagename)
end
end
end
return retobjs
end
-- Parse an inflection. The raw arguments come from `args[field]`, which is parsed for inline modifiers. Multiple
-- comma-separated values are allowed.
local function parse_inflection(data, args, field, is_head)
local argfield = field
if type(argfield) == "table" then
argfield = argfield[1]
end
return parse_inflection_forms(data, args[argfield], field, is_head)
end
-- Add a full inflection (e.g. genitive singular of nouns, abstract noun of adjectives) to `data.inflections`. `label`
-- is the label of the inflection (e.g. "abstract noun"), which can have <<...>> glossary references. `terms` is a list
-- of term objects. `accel_form` is the accelerator form (e.g. "gen|s" for genitive singular) of the inflection, or nil
-- to add no accelerator. `accel_pos` is the part of speech of the inflection, if different from the lemma.
--
-- This is a wrapper around insert_inflection() in [[Module:headword utilities]], but handles hypothetical markers in
-- the term (which are converted into the `hypothetical` face) as well as the fact that the accelerator spec may differ
-- from term to term if we need to specify a target (i.e. the value of |head= used in {{head}} or similar) that's
-- different from the term itself. This happens in particular in comparative forms, where the term reads e.g.
-- "([[покраснее|по]])[[краснее|красне́е]]" but we want the target to be just красне́е.
local function insert_inflection(data, terms, label, accel_form, accel_pos)
if not terms[1] then
return
end
for _, termobj in ipairs(terms) do
local term = termobj.term
local tr = termobj.tr
local sawhyp_term, sawhyp_tr
term, sawhyp_term = rsubb(term, HYPMARKER, "")
if tr then
tr, sawhyp_tr = rsubb(tr, HYPMARKER, "")
end
local accel
local target_term = termobj.target_term or term
-- If the target was given without a translit, don't fall back to the term translit because the target itself
-- may be different from the term.
local target_tr = termobj.target_tr or not termobj.target_term and tr or nil
if accel_form then
local lemmas = {}
local lemma_translits = {}
for i, headobj in ipairs(data.heads) do
lemmas[i] = headobj.term
lemma_translits[i] = headobj.tr
end
accel = {
form = accel_form, lemma = lemmas, lemma_translit = lemma_translits, pos = accel_pos,
target = target_term, translit = target_tr
}
end
termobj.term = term
-- Currently we don't display translits for inflections, so null out any manual translit. If we want to change
-- this, we need to set enable_auto_translit in the call to insert_inflection().
termobj.tr = nil
termobj.face = (sawhyp_term or sawhyp_tr) and "hypothetical" or nil
termobj.accel = accel
if com.needs_accents(m_links.remove_links(target_term)) then
local pos = require(en_utilities_module).singularize(data.pos_category)
-- insert(data.categories, "Requests for accents in " .. langname .. " " .. pos .. " entries")
end
end
m_headword_utilities.insert_inflection {
headdata = data,
terms = terms,
label = label,
}
end
-- Insert a fixed label `label` into the inflections for `data`. If `originating_term` is supplied, copy the qualifiers,
-- labels and references from it into the fixed label.
local function insert_fixed_inflection(data, label, originating_term)
m_headword_utilities.insert_fixed_inflection {
headdata = data,
originating_term = originating_term,
label = label,
}
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw arguments come
-- from `args[field]`, which is parsed for inline modifiers. Multiple comma-separated values are allowed. `label` is the
-- label that the inflections are given; sections enclosed in <<...>> are linked to the glossary. `accel_form` is the
-- accelerator form (or nil), and `accel_pos` if specified overrides the accelerator part of speech. Note that
-- [[Module:headword utilities]] provides a parse_and_insert_inflection() that is usually sufficient, but in our case
-- we do a bunch of additional processing when inserting inflections, so we do the parsing and inserting separately
-- using functions defined above.
local function parse_and_insert_inflection(data, args, field, label, accel_form, accel_pos)
local terms = parse_inflection(data, args, field)
insert_inflection(data, terms, label, accel_form, accel_pos)
end
local function get_split_decomposed_heads(data)
if not data.split_decomposed_heads then
data.split_decomposed_heads = com.split_translit_of_duplicate_termobjs_and_decompose(data.heads)
end
return data.split_decomposed_heads
end
local function add_common_all_pos_params(params)
params["notrcat"] = boolean_param -- don't add 'irregular pronunciations' tracking category
params["pagename"] = true
params["id"] = true
return params
end
-- The main entry point.
function export.show(frame)
local iparams = {
[1] = {required = true, desc = "part of speech"},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local poscat = iargs[1]
local params = add_common_all_pos_params {
[1] = {list = "head", disallow_holes = true},
["tr"] = {list = true, allow_holes = true, replaced_by = false,
instead = "use <tr:...> inline modifier on the headword"},
}
if pos_functions[poscat] then
for key, val in pairs(pos_functions[poscat].params) do
params[key] = val
end
end
local parargs = frame:getParent().args
local args = require("Module:parameters").process(parargs, params)
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local data = {
lang = lang,
no_redundant_head_cat = true,
pos_category = poscat,
categories = {},
genders = {},
inflections = {},
id = args.id,
pagename = pagename,
}
data.heads = parse_inflection(data, args, {1, "head"}, "is_head")
if not data.heads[1] then
data.heads = {{term = pagename}}
end
local unknown_stress = false
for i, headobj in ipairs(data.heads) do
unknown_stress = unknown_stress or headobj.unknown_stress
local tr = headobj.tr
if tr then
tr = com.decompose(tr)
local tr_gen = com.translit_no_links(headobj.term)
if tr == tr_gen then
track("redundant-translit")
elseif not args.notrcat then
-- insert(data.categories, langname .. " terms with irregular pronunciations")
end
end
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data)
end
if unknown_stress then
track("unknown-stress")
if not pos_functions[poscat] or not pos_functions[poscat].no_insert_unknown_stress_label or
not pos_functions[poscat].no_insert_unknown_stress_label(args) then
insert(data.inflections, {label = "unknown stress"})
end
end
return require(headword_module).full_headword(data)
end
-- Common params shared by {{ru-noun}} and {{ru-noun+}}.
local function add_common_noun_params(params)
params["unknown_decl"] = boolean_param -- declension unknown
params["unknown_pattern"] = boolean_param -- stress pattern (a, b, b', ...) unknown
params["unknown_gender"] = boolean_param -- gender unknown
params["unknown_animacy"] = boolean_param -- animacy unknown
params["unknown_stress"] = boolean_param -- stress unknown
params["f"] = list_param -- feminine equivalent(s)
params["m"] = list_param -- masculine equivalent(s)
params["adj"] = list_param -- relational adjective(s)
params["poss"] = list_param -- possessive adjective(s)
params["coll"] = list_param -- collective(s)
params["dim"] = list_param -- diminutive(s)
params["aug"] = list_param -- augmentative(s)
params["hypocor"] = list_param -- hypocorism(s)
params["pej"] = list_param -- pejorative(s)
params["pejcoll"] = list_param -- pejorative collective(s)
params["clip"] = list_param -- clipping(s)
params["expr"] = list_param -- expressive term(s)
params["dem"] = list_param -- demonym(s)
params["fdem"] = list_param -- female demonym(s)
return params
end
-- Implementation of {{ru-noun+}}. We should redo this implementation along the lines of {{uk-ndecl}}. For example,
-- instead of existing {{ru-noun-table|[[дви́гатель]]|m|_|[[внутренний|вну́треннего]]|+$|_|[[сгорание|сгора́ния]]|$}}, it
-- should look more like {{ru-ndecl|дви́гатель<M> [[внутренний|вну́треннего]] [[сгорание|сгора́ния]]}}.
function export.noun_plus(frame)
local iparams = {
[1] = {required = true, desc = "part of speech"},
["old"] = boolean_param,
["ndef"] = {},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local poscat = iargs[1]
local params = add_common_noun_params(add_common_all_pos_params {
["g"] = {list = true, disallow_holes = true, type = "genders", flatten = true}, -- genders
["notes"] = list_param, -- "footnotes" displayed after headword
})
local parargs = frame:getParent().args
local headword_args, args = require("Module:parameters").process(parargs, params, "return unknown")
args = clone_args(args)
-- default value of n=, used in ru-proper noun+ where ndef=sg is set
args.ndef = args.ndef or iargs.ndef
local m_noun = require("Module:ru-noun")
args = m_noun.do_generate_forms(args, iargs.old)
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local data = {
lang = lang,
no_redundant_head_cat = true,
pos_category = poscat,
categories = {},
genders = {},
inflections = {},
id = args.id,
pagename = pagename,
}
-- Do explicit genders using g=, g2=, etc.
data.genders = headword_args.g
-- If none, do inferred or explicit genders taken from declension.
if not data.genders[1] then
local gender_specs = {}
for _, g in ipairs(args.genders) do
insert(gender_specs, {spec = g})
end
data.genders = gender_specs
end
local saw_note = false
-- Given a list of {RU, TR} pairs, where TR may be nil, separate off the footnote symbols from RU and TR; link the
-- remainder if it's not already linked; remove monosyllabic accents (but not from multiword expressions); and
-- return the result in termobj format, i.e. {term = RU, tr = TR}.
local function convert_paired_terms_to_termobjs(paired_list, ishead)
if not paired_list or not paired_list[1] then
return {{term = "-"}}
end
local termobjs = {}
for _, x in ipairs(paired_list) do
local ru, tr = x[1], x[2]
-- separate_notes() just returns the note, but get_notes() adds
-- <sup>...</sup>. We want the former for checking whether the
-- note is nonempty after removing IRREGMARKER (if we use the
-- latter we'll get <sup></sup> in the case of just IRREGMARKER),
-- but the latter when generating the inflectional form.
if not ishead and (rfind(ru, "[%[|%]]") or tr and rfind(tr, "[%[|%]]")) then
track("form-with-link")
end
local ruentry, runotes = m_table_tools.separate_notes(ru)
local sawhyp
runotes = rsub(runotes, IRREGMARKER, "") -- remove note of irregularity
runotes, sawhyp = rsubb(runotes, HYPMARKER, "")
if runotes ~= "" then
saw_note = true
end
runotes = m_table_tools.superscript_notes(runotes)
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
trnotes = rsub(trnotes, IRREGMARKER, "") -- remove note of irregularity
trnotes = m_table_tools.superscript_notes(trnotes)
end
ruentry, trentry = com.remove_monosyllabic_accents(ruentry, trentry)
if sawhyp then
insert(termobjs,
{term = ruentry .. runotes .. HYPMARKER, tr = trentry and trentry .. trnotes .. HYPMARKER or nil}
)
elseif ishead then
insert(termobjs,
{term = ruentry .. runotes, tr = trentry and trentry .. trnotes or nil})
else
local ruspan, trspan
if ruentry == "-" then
ruspan = "-"
elseif rfind(ruentry, "[%[|%]]") then
-- don't add links around a form that's already linked
ruspan = ruentry .. runotes
else
ruspan = "[[" .. ruentry .. "]]" .. runotes
end
if trentry then
trspan = trentry .. trnotes
end
insert(termobjs, {term = ruspan, tr = trspan})
end
end
return com.combine_translit_of_duplicate_termobjs_and_recompose(termobjs)
end
local argsn = args.n or args.ndef
local heads, genitives, plurals, genpls
if argsn == "p" then
heads = convert_paired_terms_to_termobjs(args.nom_pl_linked, "ishead")
genitives = convert_paired_terms_to_termobjs(args.gen_pl)
plurals = {{term = "-"}}
genpls = {{term = "-"}}
else
heads = convert_paired_terms_to_termobjs(args.nom_sg_linked, "ishead")
genitives = convert_paired_terms_to_termobjs(args.gen_sg)
plurals = argsn == "s" and {{term = "-"}} or convert_paired_terms_to_termobjs(args.nom_pl)
genpls = argsn == "s" and {{term = "-"}} or convert_paired_terms_to_termobjs(args.gen_pl)
end
data.heads = heads
if com.any_termobjs_have_translit(data.heads) and not args.notrcat then
-- insert(data.categories, langname .. " terms with irregular pronunciations")
end
do_noun(data, headword_args, argsn == "s", genitives, plurals, genpls, poscat)
local notes = headword_args.notes
local notes_segments = {}
if saw_note then
for _, note in ipairs(notes) do
insert(notes_segments, " " .. make_qualifier_text(note))
end
end
local notes_text = concat(notes_segments, "")
return require(headword_module).full_headword(data) .. notes_text
end
-- Implementation of {{ru-noun}} and {{ru-proper noun}}.
local function get_noun_pos(pos)
return {
params = add_common_noun_params({
[2] = {list = "g", disallow_holes = true, required = true, default = "?", type = "genders",
flatten = true}, -- genders
[3] = {list = "gen", disallow_holes = true}, -- genitive singulars, or - for indeclinable
[4] = {list = "pl", disallow_holes = true}, -- nominative plurals
[5] = {list = "genpl", disallow_holes = true}, -- genitive plurals
["altyo"] = boolean_param, -- called from {{ru-noun-alt-ё}} or variants
["manual"] = boolean_param, -- allow manual specification of principal parts
}),
func = function(args, data)
data.genders = args[2]
local genitives = parse_inflection(data, args, {3, "gen"})
local plurals = parse_inflection(data, args, {4, "pl"})
local genpls = parse_inflection(data, args, {5, "genpl"})
local unknown_stress = false
for _, headobj in ipairs(data.heads) do
unknown_stress = unknown_stress or headobj.unknown_stress
end
if not args.altyo and not args.manual and (not genitives[1] or genitives[1].term ~= "-") and
mw.title.getCurrentTitle().nsText == "" and
not args.unknown_decl and not unknown_stress and not args.unknown_stress and
not args.unknown_pattern and not args.unknown_gender and
not args.unknown_animacy then
error("[[Template:ru-noun]] can now only be used with indeclinable and manually-declined nouns; use [[Template:ru-noun+]] instead")
end
do_noun(data, args, pos == "proper nouns", genitives, plurals, genpls, pos)
end,
no_insert_unknown_stress_label = function(args)
return true -- we do it ourselves
end,
}
end
pos_functions["နာမ်မကိတ်ညဳ"] = get_noun_pos("နာမ်မကိတ်ညဳ")
pos_functions["သဗ္ဗနာမ်"] = get_noun_pos("သဗ္ဗနာမ်")
-- Display additional inflection information for a noun.
pos_functions["နာမ်"] = get_noun_pos("နာမ်")
-- Guts of {{ru-noun}} and {{ru-noun+}}.
do_noun = function(data, args, no_plural, genitives, plurals, genitive_plurals, pos)
local recognized_genders = {
"", -- not allowed when singular; this is needed because some invariant plural-only words have no gender to speak of
"m",
"f",
"n",
"mf",
"mfbysense",
}
local recognized_animacies = {
"",
"?",
"an",
"in",
}
local recognized_numbers = {
"",
"p",
}
local function insert_if_not_blank(seq, part)
if part ~= "" then
insert(seq, part)
end
end
local singular_genders = {} -- a set
local plural_genders = {} -- a set
-- Generate the allowed gender/number/animacy specs.
for _, number in ipairs(recognized_numbers) do
for _, gender in ipairs(recognized_genders) do
for _, animacy in ipairs(recognized_animacies) do
local set = number == "" and singular_genders or plural_genders
if gender ~= "" or number == "p" then -- disallow blank gender unless plural
local gender_number = {}
insert_if_not_blank(gender_number, gender)
insert_if_not_blank(gender_number, animacy)
insert_if_not_blank(gender_number, number)
local spec = concat(gender_number, "-")
set[spec] = true
end
end
end
end
for _, gspec in ipairs(data.genders) do
local g = gspec.spec
if g == "m" then
g = "m-?"
elseif g == "m-p" then
g = "m-?-p"
elseif g == "f" and plurals[1] ~= "-" and not no_plural then
g = "f-?"
elseif g == "f-p" then
g = "f-?-p"
elseif g == "p" then
g = "?-p"
end
if not singular_genders[g] and not plural_genders[g] and g ~= "?" and g ~= "?-in" and g ~= "?-an" then
error("Unrecognized gender: " .. g)
end
gspec.spec = g
-- Categorize by number
if plural_genders[g] then
if g == "?-p" or g == "an-p" or g == "in-p" then
insert(data.categories, langname .. " pluralia tantum with incomplete gender")
end
end
end
-- Add the genitive forms
if genitives[1] and genitives[1].term == "-" then
insert(data.inflections, {label = glossary_link("ပါဲဗလေတ်ဟွံမာန်")})
insert(data.categories,"နာမ်" .. langname .. "ပါ်ပါဲထောံဟွံဂွံဂမၠိုၚ်")
else
insert_inflection(data, genitives, "ဗဳဇဂကူ")
end
local plural_only = not not plural_genders[data.genders[1].spec]
-- Add the plural forms.
if genitives[1] and genitives[1].term == "-" then
if plurals[1] or genitive_plurals[1] then
error("Can't specify nominative or genitive plurals of a plural-only term")
end
elseif plural_genders[data.genders[1].spec] then
insert(data.inflections, {label = glossary_link("ပါဲနူကိုန်ဗဟုဝစ်")})
elseif plurals[1] and plurals[1].term == "-" then
if pos ~= "နာမ်မကိတ်ညဳ" then
insert(data.inflections, {label = glossary_link("မတော်ဟွံမာန်")})
insert(data.categories,"နာမ်" .. langname .. "မတော်ဟွံဂွံဂမၠိုၚ်")
end
else
insert_inflection(data, plurals, "ကိုန်ဗဟုဝစ်မဆေၚ်စပ်ကဵုနာမ်")
insert_inflection(data, genitive_plurals, "ဗဳဇဂကူကိုန်ဗဟုဝစ်")
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw arguments
-- come from `args[field]`, which is parsed for inline modifiers. `label` is the label that the inflections are
-- given; <<..>> in the label is linked to the glossary). `accel_form` is the accelerator form, or nil.
local function handle_infl(field, label, accel_form)
parse_and_insert_inflection(data, args, field, label, accel_form)
end
-- Add the masculine forms; intentionally no accelerator as the masculine forms are lemmas and need manual handling
handle_infl("m", "မညဳညတ်သၟတ်တးကဵုလိၚ်တြုံ")
-- Add the feminine forms
handle_infl("f", "မညဳညတ်သၟတ်တးကဵုလိၚ်ဗြဴ", "f")
-- Add the relational adjective forms; intentionally no accelerator, need manual handling
handle_infl("adj", "<<နာမဝိသေသနဒၞာဲမဆက်စပ်>>")
-- Add the possessive adjective forms; intentionally no accelerator, need manual handling
handle_infl("poss", "<<နာမဝိသေသနဓမံက်ထ္ၜးမဒှ်တၠဒြပ်>>")
-- Add the collective forms; intentionally no accelerator, need manual handling
handle_infl("coll", "<<ပရေၚ်ထၜိုန်ပကောံ>>")
-- Add the diminutive forms
handle_infl("dim", "<<ပရေၚ်လ္ၚတ်ဇတ်>>", "diminutive")
-- Add the augmentative forms
handle_infl("aug", "<<ပရေၚ်မဖပေၚ်တိုန်>>", "augmentative")
-- Add the hypocorisms
handle_infl("hypocor", "<<ဝါဒပတဟ်>>", "hypocorism")
-- Add the pejorative forms
handle_infl("pej", "<<စမ်ၜတ်ရံၚ်>>", "pejorative")
-- Add the pejorative collective forms; intentionally no accelerator, need manual handling
handle_infl("pejcoll", "<<စမ်ၜတ်ရံၚ်>> <<collective>>")
-- Add the clippings
handle_infl("clip", "<<ပွမသ္ၚေပ်>>", "clipping")
-- Add the expressive terms
handle_infl("expr", "ဝေါဟာ<<မဓမံက်ထ္ၜးပ္တိတ်>>", "expressive term")
-- Add the demonyms
handle_infl("dem", "<<အပၠေံရုပ်ရာ>>", "demonym")
-- Add the female demonyms
handle_infl("fdem", "<<အပၠေံရုပ်ရာ>>ဣတ္တိလိၚ်", "female demonym")
if args.unknown_decl then
track("ဟွံတီကၠးပရေၚ်လဟုတ်စှ်ေ")
insert(data.inflections, {label = "ဟွံတီကၠးပရေၚ်လဟုတ်စှ်ေ"})
end
local unknown_stress = false
for _, headobj in ipairs(data.heads) do
unknown_stress = unknown_stress or headobj.unknown_stress
end
if unknown_stress or args.unknown_stress then
track("ဟွံတီကၠးပရေၚ်ဇြိုဟ်နက်")
insert(data.inflections, {label = "ဟွံတီကၠးပရေၚ်ဇြိုဟ်နက်"})
end
if args.unknown_pattern then
track("ပုံသက်သဳဗီုတီကၠး")
insert(data.inflections, {label = "ပုံသက်သဳဗီုလအာအရေဝ်ဟွံတီကၠး"})
end
if args.unknown_gender then
track("ဟွံတီကၠးလိၚ်")
insert(data.inflections, {label = "ဟွံတီကၠးလိၚ်"})
end
if args.unknown_animacy then
track("မၞုံလဝီုဟွံတီကၠး")
insert(data.inflections, {label = "မၞုံလဝီုဟွံတီကၠး"})
end
end
local function generate_informal_comp(compobj)
local ru, tr = compobj.term, compobj.tr
if rfind(ru, "е́?е$") then
ru, tr = com.strip_ending(ru, tr, "е") -- Cyrillic е
compobj = shallowCopy(compobj)
compobj.term, compobj.tr = com.concat_russian_tr(ru, tr, "й", nil)
return compobj
else
return nil
end
end
local function convert_to_po_variant(compobj)
local ru, tr = compobj.term, compobj.tr
if rfind(ru, "е$") or rfind(ru, "е́?й$") then
ru = "[[по" .. ru .. "|(по)]][[" .. ru .. "]]"
tr = tr and "(po)" .. tr or nil
compobj.term, compobj.tr = ru, tr
end
end
local function convert_to_nai_variant(compobj)
local ru, tr = compobj.term, compobj.tr
if ru:find("^наи") then
-- e.g. наибо́льший, наиме́ньший
return
end
ru = "[[наи" .. ru .. "|(наи)]][[" .. ru .. "]]"
tr = tr and "(nai)" .. tr or nil
compobj.term, compobj.tr = ru, tr
end
local allowed_endings = {
"ый",
"ий",
"о́й",
--old
"ій",
-- last two for adverbs
"о",
"о́",
}
local velar_to_translit = {
["к"] = "k",
["г"] = "g",
["х"] = "x"
}
local velar_to_palatal = {
["к"] = "ч",
["г"] = "ж",
["х"] = "ш",
["k"] = "č",
["g"] = "ž",
["x"] = "š"
}
-- Generate the comparative(s) given the positive(s). `positives` is a list of term objects, with the translit already
-- split and decomposed. `compspecobj` is the term object containing the comparative spec (either + or a spec giving an
-- adjectival accent pattern, such as +c'). If + is given, the default is +a unless the positive is ending-stressed, in
-- which case the default is +b. Return value is a list of term objects.
local function generate_comparative(positives, compspecobj)
local comps = {}
local compspec = compspecobj.term
if compspecobj.tr then
error("Can't specify manual translit with a '+...' comparative spec")
end
if not rfind(compspec, "^%+") then
error("Compspec '" .. compspec .. "' must begin with + in this function")
end
if compspec ~= "+" and not rfind(compspec, "^%+[abc]'*$") then
error("Compspec '" .. compspec .. "' has an illegal format, should be e.g. + or +c''")
end
compspec = rsub(compspec, "^%+", "")
for _, positive in ipairs(positives) do
local ru, tr = positive.term, positive.tr
ru = m_links.remove_links(ru)
local removed_ending = false
for _, allowed_ending in ipairs(allowed_endings) do
if rfind(ru, allowed_ending .. "$") then
if allowed_ending == "о́й" or allowed_ending == "о́" then
if compspec == "a" then
error("Short stress pattern a not allowed with ending-stressed adjectives/adverbs")
elseif compspec == "" then
compspec = "b"
end
end
ru, tr = com.strip_ending(ru, tr, allowed_ending)
removed_ending = true
break
end
end
if not removed_ending then
error("Russian '" .. ru .. "' doesn't end with expected ending")
end
local comp, comptr
if rfind(ru, "[кгх]$") then
local stemru, lastruchar = rmatch(ru, "^(.*)(.)$")
local stemtr, lasttrchar
if tr then
stemtr, lasttrchar = rmatch(tr, "^(.*)(.)$")
if velar_to_translit[lastruchar] ~= lasttrchar then
error("Translit '" .. tr .. "' doesn't end with transliterated equivalent of last char '" ..
lastruchar .. "' of Russian '" .. ru .. "'")
end
end
comp, comptr = com.make_ending_stressed(stemru, stemtr)
comp = comp .. velar_to_palatal[lastruchar] .. "е" -- Cyrillic е
if comptr then
comptr = comptr .. velar_to_palatal[lasttrchar] .. "e" -- Latin e
end
elseif compspec == "" or compspec == "a" then
comp = ru .. "ее" -- Cyrillic ее
if comptr then
comptr = tr .. "ee" -- Latin ee
end
else -- end-stressed comparative, including pattern a'
comp, comptr = com.make_unstressed_once(ru, tr)
comp = comp .. "е́е" -- Cyrillic е́е
if comptr then
comptr = comptr .. "e" .. AC .. "e" -- Latin decomposed ée
end
end
local compobj = shallowCopy(positive)
compobj.term = comp
compobj.tr = comptr
m_headword_utilities.combine_termobj_qualifiers_labels(compobj, compspecobj)
insert(comps, compobj)
end
return comps
end
-- Meant to be called from a bot
function export.generate_comparative(frame)
local iparams = {
[1] = {required = true, desc = "ပတဝ်ပတုပ်ရံၚ်"},
[2] = {default = "+"},
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local comps = iargs[1]
local compspec = iargs[2]
comps = rsplit(comps, ",")
for i, comp in ipairs(comps) do
local ru, tr = com.split_russian_tr(comp)
comps[i] = {term = ru, tr = tr}
end
comps = generate_comparative(comps, {term = compspec})
comps = com.combine_translit_of_duplicate_termobjs_and_recompose(comps)
return require(json_module).toJSON(comps)
end
-- Handle comparative and superlative inflections. If an explicit form is given such as коро́че or красне́е, we add
-- it in a "hacked" format that notes that e.g. покоро́че or покрасне́е is a possible variant. We also generate an
-- informal form in -ей if possible, e.g. красне́й, with по-hacking applied (but no such variant is possible for коро́че).
-- We also handle autogenerating comparatives when specified as + or +b, +c'', etc. (All specifications with an accent
-- pattern are equivalent other than +a.) Finally, we allow and handle periphrastic comparatives noted using "peri".
local function handle_comparatives_and_superlatives(data, args)
local noinf = args.noinf
local comps = parse_inflection(data, args, {2, "comp"})
comps = com.split_translit_of_duplicate_termobjs_and_decompose(comps)
if comps[1] and comps[1].term == "-" then
local nocomp = table.remove(comps, 1)
if comps[1] then
insert_fixed_inflection(data, "ဗွဲတၟေၚ်<<ပတဝ်ပတုပ်ရံၚ်>>ဟွံသေၚ်", nocomp)
else
insert_fixed_inflection(data, "<<ပတဝ်ပတုပ်ရံၚ်>>ဟွံသေၚ်", nocomp)
end
track("nocomp")
end
if comps[1] then
local comp_parts = {}
local function insert_comp(compobj)
local informal
if not noinf then
informal = generate_informal_comp(compobj)
if informal then
convert_to_po_variant(informal)
end
end
convert_to_po_variant(compobj)
m_headword_utilities.insert_termobj_combining_duplicates(comp_parts, compobj)
if informal then
m_headword_utilities.insert_termobj_combining_duplicates(comp_parts, informal)
end
end
for _, compobj in ipairs(comps) do
local term = compobj.term
if term == "peri" then
if compobj.tr then
error("Can't specify manual translit with 'peri' comparative spec")
end
for _, positive in ipairs(get_split_decomposed_heads(data)) do
local pericomp = shallowCopy(positive)
pericomp.term, pericomp.tr = com.concat_russian_tr("[[бо́лее]] ", nil, pericomp.term, pericomp.tr)
m_headword_utilities.combine_termobj_qualifiers_labels(pericomp, compobj)
m_headword_utilities.insert_termobj_combining_duplicates(comp_parts, pericomp)
end
track("pericomp")
elseif rfind(term, "^+") then
local autocomps = generate_comparative(get_split_decomposed_heads(data), compobj)
for _, autocomp in ipairs(autocomps) do
insert_comp(autocomp)
end
else
insert_comp(compobj)
end
end
comp_parts = com.combine_translit_of_duplicate_termobjs_and_recompose(comp_parts)
for _, compobj in ipairs(comp_parts) do
local ru, tr = compobj.term, compobj.tr
-- WARNING: This has intimate knowledge of how convert_to_po_variant() works. To avoid this, we could
-- maintain the un-po-hacked target in each form in comp_parts, but then we'd have to modify
-- com.combine_translit_of_duplicate_termobjs_and_recompose() to preserve the extra target info when
-- combining duplicate forms, or use a map from hacked Russian form to target.
local un_po_hacked_ru = m_links.remove_links(rsub(ru, "^%[%[.-%]%]", ""))
local un_po_hacked_tr = tr and rsub(tr, rsub(tr, "^%(po%)", ""), ", %(po%)", ", ") or nil
compobj.target_term = un_po_hacked_ru
compobj.target_tr = un_po_hacked_tr
end
insert_inflection(data, comp_parts, "<<ပတဝ်ပတုပ်ရံၚ်>>", "comparative")
end
-- Add the superlatives
local sups = parse_inflection(data, args, {3, "sup"})
sups = com.split_translit_of_duplicate_termobjs_and_decompose(sups)
if sups[1] then
local sup_parts = {}
for _, supobj in ipairs(sups) do
local term = supobj.term
if term == "peri" then
if supobj.tr then
error("Can't specify manual translit with 'peri' superlative spec")
end
for _, positive in ipairs(get_split_decomposed_heads(data)) do
local perisup = shallowCopy(positive)
perisup.term, perisup.tr = com.concat_russian_tr("[[са́мый]] ", nil, perisup.term, perisup.tr)
m_headword_utilities.combine_termobj_qualifiers_labels(perisup, supobj)
m_headword_utilities.insert_termobj_combining_duplicates(sup_parts, perisup)
end
track("perisup")
else
convert_to_nai_variant(supobj)
m_headword_utilities.insert_termobj_combining_duplicates(sup_parts, supobj)
end
end
sup_parts = com.combine_translit_of_duplicate_termobjs_and_recompose(sup_parts)
for _, supobj in ipairs(sup_parts) do
local ru, tr = supobj.term, supobj.tr
-- WARNING: This has intimate knowledge of how convert_to_nai_variant() works. To avoid this, we could
-- maintain the un-nai-hacked target in each form in sup_parts, but then we'd have to modify
-- com.combine_translit_of_duplicate_termobjs_and_recompose() to preserve the extra target info when
-- combining duplicate forms, or use a map from hacked Russian form to target.
local un_nai_hacked_ru = m_links.remove_links(rsub(ru, "^%[%[.-%]%]", ""))
local un_nai_hacked_tr = tr and rsub(tr, rsub(tr, "^%(nai%)", ""), ", %(nai%)", ", ") or nil
supobj.target_term = un_nai_hacked_ru
supobj.target_tr = un_nai_hacked_tr
end
insert_inflection(data, sup_parts, "<<သဒ္ဒာ>>", "superlative")
end
end
-- Display additional inflection information for an adjective
pos_functions["နာမဝိသေသန"] = {
params = {
["indecl"] = boolean_param, --indeclinable
["noinf"] = boolean_param, --suppress informal comparatives
[2] = list_comp, --comparative(s)
[3] = list_sup, --superlative(s)
["adv"] = list_param, --corresponding adverb(s)
["absn"] = list_param, --corresponding abstract noun(s)
["dim"] = list_param, --corresponding diminutive(s)
["aug"] = list_param, --corresponding augmentative(s)
["intens"] = list_param, --corresponding intensive(s)
["attenu"] = list_param, --corresponding attenuative(s)
["pej"] = list_param, --corresponding pejorative(s)
["expr"] = list_param, --corresponding expressive term(s)
},
func = function(args, data)
if args.indecl then
insert(data.inflections, {label = "ပြံၚ်လှာဲဟွံမာန်"})
insert(data.categories,"နာမဝိသေသန" .. langname .. "ပါ်ပါဲထောံဟွံဂွံဂမၠိုၚ်")
end
handle_comparatives_and_superlatives(data, args)
local function parse_and_insert_adj_inflection(field, label, accel_form, accel_pos)
parse_and_insert_inflection(data, args, field, label, accel_form, accel_pos)
end
-- Add the adverbs
parse_and_insert_adj_inflection("adv", "ကြိယာဝိသေသန")
-- Add the abstract nouns
local absn_objs = parse_inflection(data, args, "absn")
local saw_plus = false
for _, absnobj in ipairs(absn_objs) do
if absnobj.term == "+" then
saw_plus = true
break
end
end
if saw_plus then
local normalized_absn_objs = {}
absn_objs = com.split_translit_of_duplicate_termobjs_and_decompose(absn_objs)
for _, absnobj in ipairs(absn_objs) do
if absnobj.term == "+" then
if absnobj.tr then
error("Can't specify manual translit with '+' default abstract noun spec")
end
local lemmas = get_split_decomposed_heads(data)
for _, lemma in ipairs(lemmas) do
local ru, tr = lemma.term, lemma.tr
if rfind(ru, "о́?й$") then
error("Can't form default abstract noun of ending-stressed adjective " .. ru)
end
if rfind(ru, "ий$") then
ru, tr = com.strip_ending(ru, tr, "ий")
elseif rfind(ru, "ій$") then
ru, tr = com.strip_ending(ru, tr, "ій")
else
ru, tr = com.strip_ending(ru, tr, "ый")
end
ru, tr = com.concat_russian_tr(ru, tr, "ость", nil)
local lemma_absn = shallowCopy(lemma)
lemma_absn.term, lemma_absn.tr = ru, tr
m_headword_utilities.combine_termobj_qualifiers_labels(lemma_absn, absnobj)
m_headword_utilities.insert_termobj_combining_duplicates(normalized_absn_objs, lemma_absn)
end
else
m_headword_utilities.insert_termobj_combining_duplicates(normalized_absn_objs, absnobj)
end
end
normalized_absn_objs = com.combine_translit_of_duplicate_termobjs_and_recompose(normalized_absn_objs)
insert_inflection(data, normalized_absn_objs, "နာမ်စိတ္တဇ", "နာမ်စိတ္တဇ", "noun")
else
insert_inflection(data, absn_objs, "နာမ်စိတ္တဇ", "နာမ်စိတ္တဇ", "noun")
end
-- Add the diminutives
parse_and_insert_adj_inflection("dim", "<<လဟုတ်စှ်ေ>>", "diminutive")
-- Add the augmentatives
parse_and_insert_adj_inflection("aug", "<<ပရေၚ်မဖပေၚ်တိုန်>>", "augmentative")
-- Add the intensives
parse_and_insert_adj_inflection("intens", "<<ဟၟဲတွဵုဒနက်>>", "intensive")
-- Add the attenuatives
parse_and_insert_adj_inflection("attenu", "<<ဇြဟတ်ဍိုန်>>", "attenuative")
-- Add the pejoratives
parse_and_insert_adj_inflection("pej", "<<စမ်ၜတ်ရံၚ်>>", "pejorative")
-- Add the expressive terms
parse_and_insert_adj_inflection("expr", "ဝေါဟာ<<စရိုတ်အပ္ဍဲမံက်ပြာကတ်>>", "expressive")
end
}
-- Display additional inflection information for an adverb
pos_functions["ကြိယာဝိသေသန"] = {
params = {
["noinf"] = boolean_param, --suppress informal comparatives
[2] = list_comp, --comparative(s)
[3] = list_sup, --superlative(s)
["adj"] = list_param, --corresponding adjective(s)
["dim"] = list_param, --corresponding diminutive(s)
["aug"] = list_param, --corresponding augmentative(s)
["intens"] = list_param, --corresponding intensive(s)
["attenu"] = list_param, --corresponding attenuative(s)
["pej"] = list_param, --corresponding pejorative(s)
["expr"] = list_param, --corresponding expressive term(s)
},
func = function(args, data)
local comps = args[2]
handle_comparatives_and_superlatives(data, args)
local function parse_and_insert_adv_inflection(field, label, accel_form)
parse_and_insert_inflection(data, args, field, label, accel_form)
end
-- Add the adjectives
parse_and_insert_adv_inflection("adj", "<<နာမဝိသေသန>>", "adjective")
-- Add the diminutives
parse_and_insert_adv_inflection("dim", "<<အပၠေံရုပ်ရာ>>", "diminutive")
-- Add the augmentatives
parse_and_insert_adv_inflection("aug", "<<ပရေၚ်မဖပေၚ်တိုန်>>", "augmentative")
-- Add the intensives
parse_and_insert_adv_inflection("intens", "<<ပါဲဗလေတ်ဟွံမာန်>>", "intensive")
-- Add the attenuatives
parse_and_insert_adv_inflection("attenu", "<<ဇြဟတ်ဍိုန်>>", "attenuative")
-- Add the pejoratives
parse_and_insert_adv_inflection("pej", "<<စမ်ၜတ်ရံၚ်>>", "pejorative")
-- Add the expressive terms
parse_and_insert_adv_inflection("expr", "ဝေါဟာ<<စရိုတ်အပ္ဍဲမံက်ပြာကတ်>>", "expressive")
end
}
-- Display additional inflection information for a verb and verbal combining form
local function get_verb_pos(pos)
return {
params = {
[2] = {required = true, default = "?"}, --aspect
["impf"] = list_param, -- imperfective(s),
["pf"] = list_param, -- perfective(s),
["vn"] = list_param, -- verbal noun(s),
},
func = function(args, data)
local cform = pos == "နာမ်လ္ပာ်ဝါစာဗီုပြၚ်ပွမပံၚ်စပ်ဂမၠိုၚ်"
if cform then
insert(data.categories, "ကြိယာရုဿျှာဂမၠိုၚ်")
end
-- Aspect
local aspect = args[2]
if aspect == "both" then
insert(data.genders, "biasp")
elseif aspect == "pf" or aspect == "impf" or aspect == "biasp" or aspect == "?" then
insert(data.genders, aspect)
else
error("Invalid Russian verb aspect '" .. aspect .. "', should be 'pf', 'impf', 'both', 'biasp' or '?'")
end
local function add_verb_forms(field, label, accel_form, accel_pos)
parse_and_insert_inflection(data, args, field, label, accel_form, accel_pos)
end
-- Add the imperfective forms; intentionally no accelerator, need manual handling
if args.impf[1] and aspect == "impf" then
error("Can't specify imperfective counterparts for an imperfective verb")
end
add_verb_forms("impf", "ပါဲဗလေတ်ဟွံမာန်")
-- Add the perfective forms; intentionally no accelerator, need manual handling
if args.pf[1] and aspect == "pf" then
error("Can't specify perfective counterparts for a perfective verb")
end
add_verb_forms("pf", "ဗီုပြၚ်မက္ဍိုပ်ပေၚ်")
-- Add the verbal nouns
add_verb_forms("vn", "နာမ်လ္ပာ်ဝါစာ", "နာမ်လ္ပာ်ဝါစာ", "နာမ်")
end,
}
end
pos_functions["ကြိယာ"] = get_verb_pos("ကြိယာ")
pos_functions["verbal combining forms"] = get_verb_pos("verbal combining forms")
return export
59bb02e7ty7kkhlxae3opeer0qw5j91
ထာမ်ပလိက်:ru-adj
10
24232
399851
72407
2026-07-21T12:46:54Z
咽頭べさ
33
399851
wikitext
text/x-wiki
{{#invoke:ru-headword|show|နာမဝိသေသန}}<!--
--><noinclude>{{documentation}}</noinclude>
3d6xs2f7ge8zp2o8510i5qvj8hhcx2w
မဝ်ဂျူ:ru-noun
828
25168
399793
133603
2026-07-21T02:39:42Z
咽頭べさ
33
399793
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
nouns.
Author: Benwing, rewritten from early version by Wikitiki89
Form of arguments: One of the following:
1. LEMMA|DECL|PLSTEM (all arguments optional)
2. ACCENT|LEMMA|DECL|PLSTEM (all arguments optional)
3. multiple sets of arguments separated by the literal word "or"
Arguments:
ACCENT: Accent pattern (a b c d e f b' d' f' f''). Multiple values can
be specified, separated by commas. If omitted, defaults to a or b
depending on the position of stress on the lemma or
explicitly-specified declension.
LEMMA: Lemma form (i.e. nom sg or nom pl), with appropriately-placed
stress; or the stem, if an explicit declension is specified
(in this case, the declension usually looks like an ending, and
the stem is the portion of the lemma minus the ending). In the
first argument set (i.e. first set of arguments separated
by "or"), defaults to page name; in later sets, defaults to lemma
of previous set. A plural form can be given, and causes argument
n= to default to n=p (plural only). Normally, an accent is
required if multisyllabic, and unaccented monosyllables with
automatically be stressed; prefix with * to override both behaviors.
DECL: Declension field. Normally omitted to autodetect based on the
lemma form; see below.
PLSTEM: special plural stem (defaults to stem of lemma)
Additional named arguments:
a: animacy (a/an/anim = animate, i/in/inan = inanimate, b/bi/both/ai = both
(listing animate first in the headword), ia = both (listing inanimate
first in the headword), otherwise inanimate)
n: number restriction (p = plural only, s = singular only, b = both;
defaults to both unless the lemma is plural, in which case it
defaults to plural only)
CASE_NUM or acc_NUM_ANIM or par/loc/voc: override (or multiple
values separated by commas) for case/number combination;
forms auto-linked; can have raw links in it, can have an
ending "note" (*, +, 1, 2, 3, etc.)
pltail: Specify something (usually a * or similar) to attach to
the end of the last plural form when there's more than one. Used in
conjunction with notes= to indicate that alternative plural forms
are obsolete, poetic, etc.
pltailall: Similar pltail= but attaches to all plural forms.
Typically used in conjunction with notes= to make a comment about
the plural as a whole (e.g. it's mostly hypothetical, rare and
awkward, etc.).
sgtail, sgtailall: Same as pltail=, pltailall= but for the singular.
obltail, obltailall: Same as pltail=, pltailall= but for oblique cases
(not the nominative or accusative).
CASE_NUM_tail: Attach the argument to the end of the last form
(whether there's one or more than one) for the particular
case/number combination. Note that this doesn't work quite like
pltail= or sgtail= in that it doesn't skip adding the argument
when there's only one form.
CASE_NUM_tailall: Attach the argument to the end of all forms
specified for the particular case/number combination. Similar to
pltailall= or sgtailall=.
suffix: Add a suffix such as ся to all forms.
prefix: Add a prefix to all forms.
plhyp, plhypall, CASE_NUM_hyp, etc.: Same as pltail, pltailall,
CASE_NUM_tal, etc. but specify that the marked forms are
mostly hypothetical or rare/awkard. Generally you will want
plhypall=y to mark the plural as hypothetical.
Per word named arguments:
All of the above named arguments have per-word variants, e.g.
a1, a2, ...; n1, n2, ...; CASE_NUM1, CASE_NUM2, ...;
pltail1, pltail2, ...; etc. These apply to the individual words of a
form.
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
par: partitive
loc: locative
voc: vocative
Number abbreviations:
sg: singular
pl: plural
Animacy abbreviations:
an: animate
in: inanimate
Declension field:
One of the following for regular nouns:
(blank)
GENDER
-VARIANT
GENDER-VARIANT
$
DECLTYPE
DECLTYPE/DECLTYPE
(also, can append various special-case markers to any of the above)
Or one of the following for adjectival nouns:
+
+ь
$
+short, +mixed or +proper
+DECLTYPE
GENDER if present is m, f, n or 3f; for regular nouns, required if the
lemma ends in -ь or is plural, ignored otherwise. 3f is the same
as f but in the case of a plural lemma in -и, detects a
third-declension feminine with singular in -ь rather than a
first-declension feminine with singular in -а or -я.
VARIANT is one way of requesting variant declensions (see also special
case (1) for variant nom pls, and special case (2) for variant
gen pls). The currently allowed values are -ья (will select a
mixed declension that has some normal declension in its singular
and the -ья plural declension); -ин (for animate masculine nouns
in -ин with plural in -е -- note that this is autodetected in the
majority of cases where the ending in -янин or -анин); -ишко
(used for inanimate neuter-form diminutive masculine nouns in
-ишко [also сараю́шко] with nom pl -и and colloquial feminine-ending
alternants in some singular cases); -ище (similar to -ишко but
used for *animate* augmentative masculine neuter-form nouns in
-ище). Variants -ишко and -ище must be given with with special
case (1).
$ is indeclinable words. It is principally useful in multiword
expressions where some of the words are indeclinable.
DECLTYPE is an explicit declension type. Normally you shouldn't use
this, and should instead let the declension type be autodetected
based on the ending, supplying the appropriate hint if needed
(gender for regular nouns, +ь for adjectives). If provided, the
declension type is usually the same as the ending, and if present,
the lemma field should be just the stem, without the ending.
Possibilities for regular nouns are (blank) or # for hard-consonant
declension, а, я, о, е or ё, е́, й, ья, ье or ьё, ь-m, ь-f,
ин, ёнок or онок or енок, ёночек or оночек or еночек, мя,
-а or #-а, ь-я, й-я, о-и or о-ы, -ья or #-ья, $ (indeclinable).
Old-style (pre-reform) declensions use ъ instead of (blank), ъ-а
instead of -а, ъ-ья instead of -ья, and инъ, ёнокъ/онокъ/енокъ,
ёночекъ/оночекъ/еночекъ instead of the same without terminating ъ.
The declensions can also be written with an accent on them; this
chooses the same declension (except for е vs. е́), but causes
ACCENT to default to pattern b instead of a.
For adjectival nouns, you should normally supply just + and let
the ending determine the declension; supply +ь in the case of a
possessive adjectival noun in -ий, which have an extra -ь- in
most endings compared with normal adjectival nouns in -ий, but
which can't be distinguished based on the nominative singular.
You can also supply +short, +mixed or +proper, which constrains
the declension appropriately but still autodetects the
gender-specific and stress-specific variant. If you do supply
a specific declension type, as with regular nouns you need to
omit the ending from the lemma field and supply just the stem.
Possibilities are +ый, +ое, +ая, +ій, +ее, +яя, +ой, +о́е, +а́я,
+ьій, +ье, +ья, +-short or +#-short (masc), +о-short,
+о-stressed-short or +о́-short, +а-short, +а-stressed-short or
+а́-short, and similar for -mixed and -proper (except there aren't
any stressed mixed declensions).
DECLTYPE/DECLTYPE is used for nouns with one declension in the
singular and a different one in the plural, for cases that
PLVARIANT and special case (1) below don't cover.
Special-case markers:
(1) for Zaliznyak-style alternative nominative plural ending:
-а or -я for masculine, -и or -ы for neuter
(2) for Zaliznyak-style alternative genitive plural ending:
-ъ/none for masculine, -ей for feminine, -ов(ъ) for neuter,
-ей for plural variant -ья
* for reducibles (nom sg or gen pl has an extra vowel before the
final consonant as compared with the stem found in other cases)
;ё for Zaliznyak-style alternation between last е in stem and ё
TODO:
1. Multi-word issues:
-- FIXME: Make sure internal_notes handled correctly; we may run into issues
with multiple internal notes from different words, if we're not careful
to use different footnote symbols for each type of footnote (which we
don't do currently). [NOT DONE, MAY NOT DO]
-- Handling default lemma: With multiple words, we should probably split
the page name on spaces and default each word in turn [NOT DONE, MAY
NOT DO]
2a. FIXME: For -ишко diminutives and -ище augmentatives, should add an
appropriate category of some sort (currently marked by colloqfem= in
category).
2b. FIXME: Adding a note to dat_sg also adds it to loc_sg when it exists;
seems wrong. See луг.
2c. FIXME: When you have both d' and f in feminines and you use sgtail=*,
you get two *'s. See User:Benwing2/test-ru-noun-debug.
3. ADJECTIVE FIXMES:
3a. FIXME: Change calls to ru-adj11 to use the new proper name support in
ru-adjective.
3b. FIXME: Test that omitting a manual form in ru-adjective leaves the form as
a big dash.
3c. FIXME: какой-либо and какой-то display genitives with translit -go
instead of -vo. To fix this properly requires implementing real
manual translit for adjectives.
3d. FIXME: Implement real manual translit for adjectives.
5. [FIXME: Consider adding an indicator in the header line when the ё/e
alternation occurs. This is a bit tricky to calculate: If special case
;ё is given, but also if ё occurs in the stem and the accent pattern is
as follows -- for sg-only, b' d' f' f'', also b d f if the noun is masc
or 3rd-decl fem (i.e. nom-sg ending is non-syllabic); for pl-only,
e f f' f'', also b b' c if the gen pl is non-syllabic; for sg/pl,
any but a or b, also b if either nom sg or gen pl is non-syllabic. But
it gets more complicated due to overrides. An alternative is to check
all forms to see if ё is present in some but not all; but this is
tricky also because e.g. reducibles frequently have ё/null alternation,
which doesn't count, and some endings have е or ё in them, which also
doesn't count. If we were to do it this way, we'd have to (a) count
the number of е's in the form(s) with ё and verify that there's at least
one form without ё and with one more е than in the form(s) with ё
(and it gets trickier if different forms with ё have different numbers of
е in them, although that is probably rare); and (b) ignore the appropriate
endings (the best way to do this would probably be to look at the actual
suffixes that were generated in args.suffixes and chop off any matching
ending in the actual form(s), but also chop off final -е/ё, as well as
-ев(ъ)/-ёв(ъ)/-ей/-ёй in the gen pl, which is frequently overridden,
unless perhaps the stem ends in the same way). It'd probably not
possible to do this in a 100% foolproof way but can be "good enough" for
nearly all circumstances.] [MIGHT BE TOO MUCH WORK]
6. HEADWORD FIXMES:
6a. FIXME: In ru-headword, create a category for words whose gender doesn't
match the form. (This is easy to do for ru-noun+ but harder for ru-noun.
We would need to do limited autodetection of the ending: for singulars,
-а/я should be feminine, -е/о/ё should be neuter, -ь should be masculine
or feminine, anything else should be masculine; for plurals, -и/ы should
be masculine or feminine, -а/я should be neuter except that -ія can be
feminine or neuter due to old-style adjectival pluralia tantum nouns,
anything else can be any gender.)
6b. FIXME: Recognize indeclinable nouns and indicate as indeclinable. Probably
should work by checking the case forms to see if they're the same.
9. FIXME: Change stress-pattern detection and overriding to happen inside of
looping over the two parts of a slash decl. Requires that the loop over
the two parts happen outside of the loop over stress patterns. Requires
that the category code get split into two parts, one to handle combined
singular/plural categories that goes outside the two loops, and one to
handle everything else that goes inside the two loops.
10. FIXME: override_matches_suffix() had a free variable reference to ARGS
in it, which should have triggered an error whenever there was a nom_sg or
nom_pl override but didn't. Is there an error causing this never to be
called? Check.
11a. FIXME: In a multiword lemma, using loc2=+ causes only the second word
to get linked instead of the whole expression. Same for par2=+, voc2=+.
11b. FIXME: Using loc=+ with a multiword lemma should do the right thing, same
as if locN=+ is specified for each individual word. Instead it generates
the locative as a whole from the dative, which fails e.g. if some of the
words are adjectival. Same for par=+, voc=+.
13. Multi-word issues:
-- Setting n=pl when auto-detecting a plural lemma. How does that interact
with multi-word stuff? (DONE)
-- compute_heading() -- what to do with multiple words? I assume we should
display info on the first noun (non-indeclinable, non-adjectival), and
on the first adjectival word otherwise, and finally on an indeclinable word (DONE)
-- args.genders -- it should presumably come from the same word as is used
in compute_heading(); but we should allow the overall gender to be
overridden, at least in ru-noun+ (DONE)
-- Bug in args.suffix: Gets added to every word in attach_with() and then
again at the end, after pltail and such. Needs to be added to the
last word only, before pltail. Need also suffixN for individual words.
(DONE, NEEDS TESTING)
-- Should have ..N versions of pltail and variants. (DONE, NEEDS TESTING)
-- Need to handle overrides of acc_sg, acc_pl (DONE)
-- Overrides of nom_sg/nom_pl should also override acc_sg/acc_pl if it
was originally empty and the animacy is inanimate; similarly for
gen_sg/gen_pl and animates; this needs to work both for per-word and
overall overrides. (DONE)
-- do_generate_forms(_multi) need to run part of make_table(), enough to
combine all per_word_info into single lists of forms and store back
into args[case]. (DONE, NEEDS TESTING)
-- In generate_forms, should probably check if a=="i" and only return
acc_sg_in as acc_sg=; or if a=="a" and only return acc_sg_an as acc_sg=;
in old/new comparison code, do something similar, also when a=="b"
check if acc_sg_in==acc_sg_an and make it acc_sg; when a=="b" and the
_in and _an variants are different, might need to ignore them or check
that acc_sg_in==nom_sg and acc_sg_an==gen_sg; similarly for _pl
(DONE, NEEDS TESTING)
-- Need to test with multiple words! [DONE]
-- Current handling of <adj> won't work properly with multiple words;
will need to translate word-by-word in that case (should be solved by
manual-translit branch) [DONE]
14. In multiple-words branch, fix ru-decl-noun-multi so it recognizes
things like *, (1), (2) and ; without the need for a separator. Consider
using semicolon as a separator, since we already use it to separate ё
from a previous declension. Maybe use $ or ~ for an indeclinable word; don't
use semicolon. [IMPLEMENTED. NEED TO TEST.]
16. [Consider having ru-noun+ treat par= as a second genitive in
the headword, as is done with край] [WON'T DO]
17. [FIXME: Consider removing slash patterns and instead handling them by
allowing additional declension flags 'sg' and 'pl'. This simplifies the
various special cases caused by slash declensions. It would also be
possible to remove the special plural stem, which would get rid of more
special cases. On the other hand, it makes it more complicated to support
plural variant -ья with all singular types, and the category code that
displays things like "Russian nouns with singular -X and plural -Y"
also gets more complicated, and there's something convenient and intuitive
about plural stems, and slash declensions are also convenient and at least
somewhat intuitive. One possibility is to externally allow slash
declensions and special plural stems and rewrite them internally to
separate stems with 'sg' and 'pl' declension flags; but there are still
the two coding issues mentioned above.]
18. [FIXME: Consider redoing slash patterns so they operate at the outer
level, i.e. things like special cases apply separately in the singular
and plural part of the slash pattern.]
19. In ru-noun, don't recognize -а with m as plural unless (1)
or n=pl is also given, because there are masculine words with the
feminine ending. Check using the test code whether this changes
anything. Also check if there are other similar cases (neuter with
-и isn't parallel because -и is always plural). [IMPLEMENTED. NEED TO TEST.]
19a. Internal notes weren't propagated properly from adjectives.
[IMPLEMENTED. NEED TO TEST.]
19b. Add support for -ишко and -ище variants (p. 74 of Z),
which conversationally and/or colloquially have feminine endings in
certain cases. [IMPLEMENTED. NEED TO TEST. MAKE SURE THE INTERNAL NOTES
APPEAR.]
19d. For masculine animate neuter-form nouns, the accusative singular
ends in -а (-я soft) instead of -о. [IMPLEMENTED. NEED TO TEST.
NOTE: Currently this variant only can be selected using new-style
arguments where the gender can be given. Perhaps we should consider
allowing gender to be specified with old-style explicit declensions.]
21. Put back gender hints for pl adjectival nouns; used by ru-noun+.
[IMPLEMENTED. NEED TO TEST.]
23. Mixed and proper-noun adjectives have built-in notes. We need to
handle those notes with an "internal_notes" section similar to what is used
in the adjective module. [IMPLEMENTED. NEED TO TEST.]
24. Adjective detection code here needs to work the same as for the
adjective module, in particular in the handling of short, stressed-short,
mixed, proper, stressed-proper. [IMPLEMENTED. NEED TO TEST.]
25. Consider simplifying plural-variant code to only allow -ья as a
plural variant [and maybe even change that to be something like (1')].
[IMPLEMENTED REDUCTION OF PLURAL VARIANTS TO -ья; PLURAL-VARIANT CODE
STILL COMPLEX, THOUGH. NEED TO TEST.]
26. Automatically superscript *, numbers and similar things at the
beginning of a note. Also do this in adjective module. [IMPLEMENTED.
NEED TO TEST.]
28. Make the check for multiple stress patterns (categorizing/tracking)
smarter, to keep a list of them and check at the end, so we handle
multiple stress patterns specified through different arg sets.
[IMPLEMENTED; NEED TO TEST.]
29. More sophisticated handling of user-requested plural variant vs. special
case (1) vs. plural-detected variant. [IMPLEMENTED. NEED TO TEST FURTHER.]
30. Solution to ambiguous plural involving gender spec "3f". [IMPLEMENTED;
NEED TO TEST. Use запчасти, новости.]
33. With pluralia tantum adjectival nouns, we don't know the gender.
By default we assume masculine (or feminine for old-style -ія nouns) and
currently this goes into the category, but shouldn't. [IMPLEMENTED.]
39. [Eventually: Even with decl type explicitly given, the full stem with
ending should be included.] [MAY NEVER IMPLEMENT]
40. [Get error "Unable to dereduce" with strange noun ва́йя, what should
happen?] [WILL NOT FIX; USE AN OVERRIDE]
41. In творог, module generates partitive творогу́ when it should copy the
dative творогу́,тво́рогу. (DONE)
42. [[груз 200]] doesn't work. Interprets 200 as a footnote symbol.
43. When converting е -> ё not after cons and with translit, we should
convert e -> o to avoid double j. (DONE)
44. FIXME: In ро́вня/ровня́, similarly with неровня, marks genitive plural
ровня́ as irregular even though it isn't. (NOT OUR ERROR; THE DECLENSIONS
OF THESE NOUNS MARKED THE ENDING-STRESSED VARIANTS WITH (2).)
]=]--
local m_utilities = require("Module:utilities")
local m_table = require("Module:table")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local m_ru_adj = require("Module:ru-adjective")
local m_str_utils = require("Module:string utilities")
local scriptutils = require("Module:script utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
local Latn = require("Module:scripts").getByCode("Latn")
local format = m_str_utils.format
local rfind = m_str_utils.find
local rsubn = m_str_utils.gsub
local rmatch = m_str_utils.match
local rsplit = m_str_utils.split
local u = m_str_utils.char
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same. Eventually consider removing this;
-- but useful as new code is created.
local test_new_ru_noun_module = false
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local DIA = u(0x0308) -- diaeresis = ̈
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder, matching ru-common
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
local paucal_marker = "*"
local paucal_internal_note = "* Used with the numbers 1.5, 2, 3, 4 and higher numbers after 20 ending in 2, 3, and 4."
-- text class to check lowercase arg against to see if Latin text embedded in it
local latin_text_class = "[a-zščžěáéíóúýàèìòùỳâêîôûŷạẹịọụỵȧėȯẏ]"
-- Forward functions
local generate_forms_1
local determine_decl
local handle_forms_and_overrides
local handle_overall_forms_and_overrides
local concat_word_forms
local make_table
local detect_adj_type
local detect_stress_pattern
local override_stress_pattern
local determine_stress_variant
local determine_stem_variant
local is_reducible
local is_dereducible
local add_bare_suffix
local attach_stressed
local do_stress_pattern
local canonicalize_override
-- 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
-- version of rfind() that lowercases its string first, for case-insensitive matching
local function rlfind(term, foo)
return rfind(ulower(term), foo)
end
local function track(page)
m_debug.track("ru-noun/" .. page)
return true
end
-- version of m_table.insertIfNot() that makes sure 'false' doesn't get inserted by mistake.
local function insert_if_not(foo, bar)
assert(bar ~= false)
m_table.insertIfNot(foo, bar)
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-- FIXME: Move to utils
-- Iterate over a chain of parameters, FIRST then PREF2, PREF3, ...,
-- inserting into LIST (newly created if omitted). Return LIST.
local function get_arg_chain(args, first, pref, list)
if not list then
list = {}
end
local val = args[first]
local i = 2
while val do
table.insert(list, val)
val = args[pref .. i]
i = i + 1
end
return list
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
local function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
local function rutr_pairs_equal(term1, term2)
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
local ru1entry, ru1notes = m_table_tools.separate_notes(m_links.remove_links(ru1))
local ru2entry, ru2notes = m_table_tools.separate_notes(m_links.remove_links(ru2))
if ru1entry ~= ru2entry then
return false
end
local tr1entry, tr1notes
local tr2entry, tr2notes
if tr1 then
tr1entry, tr1notes = m_table_tools.separate_notes(tr1)
end
if tr2 then
tr2entry, tr2notes = m_table_tools.separate_notes(tr2)
end
if tr1entry == tr2entry then
return true
elseif type(tr1entry) == type(tr2entry) then
return false
else
tr1entry = tr1entry or com.translit_no_links(ru1entry)
tr2entry = tr2entry or com.translit_no_links(ru2entry)
return tr1entry == tr2entry
end
end
local function contains_rutr_pair(list, pair)
for _, item in ipairs(list) do
if rutr_pairs_equal(item, pair) then
return true
end
end
return false
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
args[pname] = ine(param)
end
return args
end
-- Old-style declensions.
local declensions_old = {}
-- New-style declensions; computed automatically from the old-style ones,
-- for the most part.
local declensions = {}
-- Internal notes for old-style declensions.
local internal_notes_table_old = {}
-- Same for new-style declensions.
local internal_notes_table = {}
-- Category and type information corresponding to declensions: These may
-- contain the following fields: 'singular', 'plural', 'decl', 'hard', 'g',
-- 'suffix', 'gensg', 'irregpl', 'alt_nom_pl', 'cant_reduce', 'ignore_reduce',
-- 'stem_suffix'.
--
-- 'singular' is used to construct a category of the form
-- "Russian nouns SINGULAR". If omitted, a category is constructed of the
-- form "Russian nouns ending in -ENDING", where ENDING is the actual
-- nom sg ending shorn of its acute accents; or "Russian nouns ending
-- in suffix -ENDING", if 'suffix' is true. The value of SINGULAR can be
-- one of the following: a single string, a list of strings, or a function,
-- which is passed one argument (the value of ENDING that would be used to
-- auto-initialize the category), and should return a single string or list
-- of strings. Such a category is only constructed if 'gensg' is true.
--
-- 'plural' is analogous but used to construct a category of the form
-- "Russian nouns with PLURAL", and if omitted, a category is constructed
-- of the form "Russian nouns with plural -ENDING", based on the actual
-- nom pl ending shorn of its acute accents. Currently no plural category
-- is actually constructed.
--
-- In addition, a category may normally constructed from the combination of
-- 'singular' and 'plural', appropriately defaulted; e.g. if both are present,
-- the combined category will be "Russian nouns SINGULAR with PLURAL" and
-- if both are missing, the combined category will be
-- "Russian nouns ending in -SGENDING with plural -PLENDING" (or
-- "Russian nouns ending in suffix -SGENDING with plural -PLENDING" if
-- 'suffix' is true). Note that if either singular or plural or both
-- specifies a list, looping will occur over all combinations. Such a
-- category is constructed only if 'irregpl' or 'alt_nom_pl' or 'suffix'
-- is true or if the declension class is a slash class.
--
-- 'decl' is "1st", "2nd", "3rd" or "indeclinable"; 'hard' is "hard", "soft"
-- or "none"; 'g' is "m", "f", "n" or "none"; these are all traditional
-- declension categories.
--
-- If 'suffix' is true, the declension type includes a long suffix
-- added to the string that itself undergoes reducibility and such, and so
-- reducibility cannot occur in the stem minus the suffix. Categories will
-- be created for the suffix.
--
-- 'alt_nom_pl' indicates that the declension has an alternative nominative
-- plural (corresponding to Zaliznyak's special case 1; compare special case 2
-- for alternative genitive plural). 'irregpl' indicates that the entire
-- plural is irregular.
--
-- In addition to the above categories, additional more specific categories
-- are constructed based on the final letter of the stem, e.g.
-- "Russian velar-stem 1st-declension hard nouns". See calls to
-- com.get_stem_trailing_letter_type(). 'stem_suffix', if present, is added to
-- the end of the stem when get_stem_trailing_letter_type() is called.
-- This is the only place that 'stem_suffix' is used. This is for use with
-- the '-ья' and '-ье' declension types, so that the trailing letter is
-- 'ь' and not whatever precedes it.
--
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
-- Category/type info corresponding to old-style declensions; see above.
local declensions_old_cat = {}
-- Category/type info corresponding to new-style declensions. Computed
-- automatically from the old-style ones, for the most part. Same format
-- as the old-style ones.
local declensions_cat = {}
-- Table listing aliases of old-style declension classes.
local declensions_old_aliases = {}
-- Table listing aliases of new-style declension classes; computed
-- automatically from the old-style ones.
local declensions_aliases = {}
local stress_patterns = {}
-- Set of patterns with ending-stressed genitive plural.
local ending_stressed_gen_pl_patterns = {}
-- Set of patterns with ending-stressed prepositional singular.
local ending_stressed_pre_sg_patterns = {}
-- Set of patterns with ending-stressed dative singular.
local ending_stressed_dat_sg_patterns = {}
-- Set of patterns with all singular forms ending-stressed.
local ending_stressed_sg_patterns = {}
-- Set of patterns with all plural forms ending-stressed.
local ending_stressed_pl_patterns = {}
local declinable_cases_except_accusative = {
"nom_sg", "gen_sg", "dat_sg", "ins_sg", "pre_sg",
"nom_pl", "gen_pl", "dat_pl", "ins_pl", "pre_pl",
}
local accusative_cases_unsplit_animacy = {
"acc_sg", "acc_pl",
}
local accusative_cases_split_animacy = {
"acc_sg_an", "acc_sg_in", "acc_pl_an", "acc_pl_in",
}
local lemma_linked_cases = {
"nom_sg_linked", "nom_pl_linked",
}
local overridable_only_cases = {
"par", "loc", "voc", "par_pl", "loc_pl", "voc_pl", "count", "pauc",
}
local overridable_only_cases_set = m_table.listToSet(overridable_only_cases)
-- List of all cases that are declined normally.
local decl_cases = m_table.append(declinable_cases_except_accusative, accusative_cases_unsplit_animacy)
-- List of all cases that can be overridden (includes all cases except the "linked" lemma case variants). Also
-- currently the same as the cases returned by export.generate_forms().
local overridable_cases = m_table.append(decl_cases, accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases that can be displayed (includes all cases except plain accusatives).
local displayable_cases = m_table.append(declinable_cases_except_accusative, lemma_linked_cases,
accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases, including those that are declined normally (nom/gen/dat/acc/ins/pre sg and pl), plus
-- animate/inanimate accusative variants (computed automatically as appropriate from the previous cases), plus
-- additional overridable cases (loc/par/voc and plural), plus the "linked" lemma case variants used in ru-noun+
-- headwords (nom_sg_linked, nom_pl_linked, whose values come from nom_sg and nom_pl but may have additional embedded
-- links if they were given in the lemma).
local all_cases = m_table.append(overridable_cases, lemma_linked_cases)
local function english_case_description(case)
if case == "par" or case == "loc" or case == "voc" then
-- For historical reasons, the singular of these cases doens't include "_sg" in their code.
case = case .. "_sg"
end
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
par="partitive", loc="locative", voc="vocative",
count="count form", pauc="paucal form",
})
engcase = rsub(engcase, "(_[a-z]*)", {
_sg=" singular", _pl=" plural",
_an="", _in="",
--_an=" animate", _in=" inanimate"
})
return engcase
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
-- FIXME! Move below the main code
-- FIXME!! Consider deleting most of this tracking code once we've enabled
-- all the categories. Note that some of the tracking categories aren't
-- completely redundant; e.g. we have tracking pages that combine decl and
-- stress classes, such as "а/a" or "о-и/d'", which are more or less
-- equivalent to stem/gender/stress categories, but we also have the same
-- prefixed by "reducible-stem/" for reducible stems.
local function tracking_code(stress, orig_decl, decl, args, n, islast)
assert(orig_decl)
assert(decl)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
if orig_decl == decl then
orig_decl = nil
end
if args.notes then
track("notes")
end
local function all_pl_irreg()
track("irreg")
for _, case in ipairs(overridable_cases) do
if rfind(case, "_pl") then
track("irreg/" .. case)
end
end
end
local function track_prefix(prefix)
local function dotrack(suf)
track(prefix .. suf)
end
dotrack(stress)
dotrack(decl)
dotrack(decl .. "/" .. stress)
if orig_decl then
dotrack(orig_decl)
dotrack(orig_decl .. "/" .. stress)
end
for _, hint_type in ipairs(hint_types) do
dotrack(hint_type)
dotrack(decl .. "/" .. hint_type)
if orig_decl then
dotrack(orig_decl .. "/" .. hint_type)
end
end
end
track_prefix("")
if args.reducible then
track("reducible-stem")
track_prefix("reducible-stem/")
end
if rlfind(args.stem, "и́?н$") and (decl == "" or decl == "#") then
track("irregular-in")
end
if args.pltail then
track("pltail")
end
if args.sgtail then
track("sgtail")
end
if args.pltailall then
track("pltailall")
end
if args.sgtailall then
track("sgtailall")
end
if args.pl ~= args.stem then
track("irreg-pl-stem")
track("irreg")
end
if args.alt_gen_pl then
track("alt-gen-pl")
track("irreg")
track("irreg/gen_pl")
end
if args.want_sc1 then
track("want-sc1")
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-и$") or rfind(decl, "-а$") or rfind(decl, "-я$") then
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-ья$") then
track("variant-ья")
all_pl_irreg()
end
if rfind(decl, "%(ишк%)$") then
track("variant-ишко")
end
if rfind(decl, "%(ищ%)$") then
track("variant-ище")
end
if args.jo_special then
track("jo-special")
end
if args.manual then
track("manual")
end
if args.explicit_gender then
track("explicit-gender")
track("explicit-gender/" .. args.explicit_gender)
end
for _, case in ipairs(overridable_cases) do
if args[case .. n] and not args.manual then
track("override")
track("override/" .. case .. n)
track("irreg")
track("irreg/" .. case .. n)
-- questionable use: track_prefix("irreg/" .. case .. "/")
-- questionable use: track_prefix("irreg/" .. case .. n .. "/")
end
if islast and args[case] and not args.manual then
track("override")
track("override/" .. case)
track("irreg")
track("irreg/" .. case)
-- questionable use: track_prefix("irreg/" .. case .. "/")
end
if args[case .. "_tail"] then
track("casenum-tail")
track("casenum-tail/" .. case)
end
if args[case .. "_tailall"] then
track("casenum-tailall")
track("casenum-tailall/" .. case)
end
end
end
local gender_to_full = {m="ပုလ္လိၚ်", f="ဣတ္တိလိၚ်", n="နပုလ္လိၚ်"}
local gender_to_short = {m="masc", f="fem", n="neut"}
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the plural part of speech.
local function insert_category(categories, cat, pos, atbeg)
if enable_categories then
-- local fullcat = "Russian " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(categories, 1, fullcat)
else
table.insert(categories, fullcat)
end
end
end
-- Insert categories into ARGS.CATEGORIES corresponding to the specified
-- stress and declension classes and to the form of the stem (e.g. velar,
-- sibilant, etc.). Also initialize values used to compute the declension
-- heading that describes similar information. N is the number of the
-- word being processed; ISLAST is true if this is the last word.
local function categorize_and_init_heading(stress, decl, args, n, islast)
local function cat_to_list(cat)
if not cat then
return {}
elseif type(cat) == "string" then
return {cat}
else
assert(type(cat) == "table")
return cat
end
end
-- Insert category CAT into the list of categories in ARGS.
-- CAT may be nil, a single string or a list of strings. We call
-- insert_category() on each string. The strings will have "Russian "
-- prepended and "~" replaced with the plural part of speech.
local function insert_cat(cat)
for _, c in ipairs(cat_to_list(cat)) do
insert_category(args.categories, c, args.pos)
end
end
-- "Resolve" the category spec CATSPEC into the sort of category spec
-- accepted by insert_cat(), i.e. nil, a single string or a list of
-- strings. CATSPEC may be any of these or a function, which takes one
-- argument (SUFFIX) and returns another CATSPEC.
local function resolve_cat(catspec, suffix)
if type(catspec) == "function" then
return resolve_cat(catspec(suffix), suffix)
else
return catspec
end
end
-- Check whether an override for nom_sg or nom_pl still contains the
-- normal suffix (which should already have accents removed) in at least
-- one of its entries. If no override then of course we return true.
local function override_matches_suffix(args, case, n, suffix)
assert(suffix == com.remove_accents(suffix))
-- NOTE: It might not be completely correct to pass in args.forms
-- here when n == ""; this is different behavior from
-- handle_overall_forms_and_overrides(). But args.forms is only used
-- to retrieve the dat_sg for handling loc/par, and we're never
-- called with loc or par as the value of CASE, so it doesn't matter.
-- We add an assert to make sure of this.
assert(case ~= "loc" and case ~= "par")
local override = canonicalize_override(args, case, args.forms, n)
if not override then
return true
end
for _, x in ipairs(override) do
local ru, tr = x[1], x[2]
local entry, notes = m_table_tools.separate_notes(ru)
entry = com.remove_accents(m_links.remove_links(entry))
if rlfind(entry, suffix .. "$") then
return true
end
end
return false
end
if args.manual then
return
end
local h = args.heading_info
assert(decl)
local decl_cats = args.old and declensions_old_cat or declensions_cat
local sgdecl, pldecl
local is_slash_decl = rfind(decl, "/")
if is_slash_decl then
local indiv_decls = rsplit(decl, "/")
sgdecl, pldecl = indiv_decls[1], indiv_decls[2]
else
sgdecl, pldecl = decl, decl
end
local sgdc = decl_cats[sgdecl]
local pldc = decl_cats[pldecl]
assert(sgdc)
assert(pldc)
local sghint_types = com.get_stem_trailing_letter_type(
args.stem .. (sgdc.stem_suffix or ""))
-- insert English version of Zaliznyak stem type
if sgdc.decl == "indeclinable" then
insert_cat("indeclinable ~")
insert_if_not(h.stemetc, "indecl")
else
local stem_type =
sgdc.decl == "3rd" and "3rd-declension" or
m_table.contains(sghint_types, "velar") and "velar-stem" or
m_table.contains(sghint_types, "sibilant") and "sibilant-stem" or
m_table.contains(sghint_types, "c") and "ц-stem" or
m_table.contains(sghint_types, "i") and "i-stem" or
m_table.contains(sghint_types, "vowel") and "vowel-stem" or
m_table.contains(sghint_types, "soft-cons") and "vowel-stem" or
m_table.contains(sghint_types, "palatal") and "vowel-stem" or
sgdc.hard == "soft" and "soft-stem" or
"hard-stem"
local short_stem_type = stem_type == "3rd-declension" and "3rd-decl" or stem_type
if sgdc.adj then
-- Don't include gender for pluralia tantum because it's mostly
-- indeterminate (certainly when specified using a plural lemma,
-- which will be usually; technically it's partly or completely
-- determinate in certain old-style adjectives that distinguish
-- masculine from feminine/neuter, but this is too rare a case
-- to worry about)
local gendertext = args.thisn == "p" and "plural-only" or gender_to_full[sgdc.g]
insert_if_not(h.adjectival, "yes")
if args.thisn ~= "p" then
insert_if_not(h.gender, gender_to_short[sgdc.g])
end
if sgdc.possadj then
insert_cat(sgdc.decl .. " possessive " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, sgdc.decl .. " poss")
insert_if_not(h.stress, stress)
elseif stem_type == "soft-stem" or stem_type == "vowel-stem" then
insert_cat(stem_type .. " " .. gendertext .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
else
insert_cat(stem_type .. " " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
else
-- NOTE: There are 8 Zaliznyak-style stem types and 3 genders, but
-- we don't create a category for masculine-form 3rd-declension
-- nouns (there is such a noun, путь, but it mostly behaves
-- like a feminine noun), so there are 23.
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form ~")
-- NOTE: Here we are creating categories for the combination of
-- stem, gender and accent. There are 10 accent patterns and 23
-- combinations of stem and gender, which potentially makes for
-- 10*23 = 230 such categories, which is a lot. Not all such
-- categories should actually exist; there were maybe 75 former
-- declension templates, each of which was essentially categorized
-- by the same three variables, but some of which dealt with
-- ancillary issues like irregular plurals; this amounts to 67
-- actual stem/gender/accent categories, although there are more
-- of them in Zaliznyak (FIXME, how many? See generate_cats.py).
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " ~")
insert_if_not(h.adjectival, "no")
insert_if_not(h.gender, gender_to_short[sgdc.g])
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
insert_cat("~ with accent pattern " .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
local sgsuffix = args.suffixes.nom_sg
if sgsuffix then
assert(#sgsuffix == 1) -- If this ever fails, then implement a loop
sgsuffix = com.remove_accents(sgsuffix[1])
-- If we are plural only or if nom_sg is overridden and has
-- an unusual suffix, then don't create category for sg suffix
if args.thisn == "p" or not override_matches_suffix(args, "nom_sg", n, sgsuffix) or islast and not override_matches_suffix(args, "nom_sg", "", sgsuffix) then
sgsuffix = nil
end
end
local plsuffix = args.suffixes.nom_pl
if plsuffix then
assert(#plsuffix == 1) -- If this ever fails, then implement a loop
plsuffix = com.remove_accents(plsuffix[1])
-- If we are a singulare tantum or if nom_pl is overridden and has
-- an unusual suffix, then don't create category for pl suffix
if args.thisn == "s" or not override_matches_suffix(args, "nom_pl", n, plsuffix) or islast and not override_matches_suffix(args, "nom_pl", "", plsuffix) then
plsuffix = nil
end
end
sgsuffix = sgsuffix and rsub(sgsuffix, "ъ$", "")
plsuffix = plsuffix and rsub(plsuffix, "ъ$", "")
local sgcat = sgsuffix and (resolve_cat(sgdc.singular, sgsuffix) or "ending in " .. (sgsuffix == "" and "a consonant" or (sgdc.suffix and "suffix " or "") .. "-" .. sgsuffix))
local plcat = plsuffix and (resolve_cat(pldc.plural, plsuffix) or "plural -" .. plsuffix)
if sgcat and sgdc.gensg then
for _, cat in ipairs(cat_to_list(sgcat)) do
insert_cat("~ " .. cat)
end
end
if sgcat and plcat and (sgdc.suffix or sgdc.alt_nom_pl or sgdc.irregpl or
is_slash_decl and plsuffix == "-ья") then
for _, scat in ipairs(cat_to_list(sgcat)) do
for _, pcat in ipairs(cat_to_list(plcat)) do
-- insert_cat("~ " .. scat .. " with " .. pcat)
end
end
end
if args.pl ~= args.stem then
-- insert_cat("~ with irregular plural stem")
end
if args.reducible and not sgdc.ignore_reduce then
-- insert_cat("~ with reducible stem")
if args.soft_n then
-- insert_cat("~ with soft final н in reduced stem")
end
insert_if_not(h.reducible, "yes")
else
insert_if_not(h.reducible, "no")
end
if args.alt_gen_pl then
-- insert_cat("~ with alternative genitive plural")
end
if sgdc.adj then
-- insert_cat("adjectival ~")
end
end
local function compute_heading(args)
local headings = {}
local h = args.heading_info
table.insert(headings, args.a == "a" and "anim" or args.a == "i" and
"inan" or "bian")
table.insert(headings, args.nonumber and "uncountable" or
args.n == "s" and "sg-only" or args.n == "p" and "pl-only" or nil)
if #h.gender > 0 then
table.insert(headings, table.concat(h.gender, "/") .. "-form")
end
if #h.stemetc > 0 then
table.insert(headings, table.concat(h.stemetc, "/"))
end
if #h.stress > 0 then
local stresses = {}
for _, stress in ipairs(h.stress) do
table.insert(stresses, (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
table.insert(headings, "accent-" .. table.concat(stresses, "/"))
end
local function handle_bool(boolvals, text, into)
into = into or headings
if m_table.contains(boolvals, "yes") and m_table.contains(boolvals, "no") then
table.insert(into, "[" .. text .. "]")
elseif m_table.contains(boolvals, "yes") then
table.insert(into, text)
end
end
handle_bool(h.adjectival, "adj")
handle_bool(h.reducible, "reduc")
return headings
end
local function compute_overall_heading_categories_and_genders(args)
local hinfo = args.per_word_heading_info
local index = 0
-- First try for non-adjectival, non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") and not m_table.contains(hinfo[i].adjectival, "yes") then
index = i
break
end
end
if index == 0 then
-- Then just non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") then
index = i
break
end
end
end
-- Finally, do anything
if index == 0 then
index = 1
end
-- Compute final heading
local headings = args.per_word_headings[index]
local categories = args.per_word_categories[index]
if args.any_irreg then
table.insert(headings, "irreg")
-- insert_category(categories, "irregular ~", args.pos)
end
for _, case in ipairs(overridable_cases) do
local is_pl = rfind(case, "_pl")
if args.n == "s" and is_pl or args.n == "p" and not is_pl then
-- Don't create singular categories when plural-only or vice-versa
elseif overridable_only_cases_set[case] then
if args.any_overridden[case] then
-- insert_category(categories, "~ with " .. english_case_description(case), args.pos)
end
elseif args.any_irreg_case[case] then
-- insert_category(categories, "~ with irregular " .. english_case_description(case), args.pos)
end
end
local heading = args.manual and "" or "(<span style=\"font-size: smaller;\">[[Appendix:Russian nouns#Declension tables|" .. table.concat(headings, " ") .. "]]</span>)"
args.heading = heading
args.categories = categories
args.genders = args.per_word_genders[index]
end
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Used by do_generate_forms().
local function arg1_is_stress(arg1)
if not arg1 then return false end
for _, arg in ipairs(rsplit(arg1, ",")) do
if not rfind(arg, "^[a-f]'?'?$") then
return false
end
end
return true
end
-- Used by do_generate_forms(), handling a word joiner argument
-- of the form 'join:JOINER'.
local function extract_word_joiner(spec)
word_joiner = rmatch(spec, "^join:(.*)$")
assert(word_joiner)
return com.split_russian_tr(word_joiner, "dopair")
end
local function determine_headword_gender(args, sgdc, gender)
-- If gender unspecified, use normal gender of declension, except when
-- adjectival nouns that are pluralia tantum, where the gender is
-- mostly indeterminate (FIXME, not completely with old-style declensions
-- but we don't handle that currently).
if not gender then
if sgdc.adj and args.thisn == "p" then
gender = nil
else
gender = sgdc.g
end
end
-- Determine headword genders
gender = gender and gender ~= "none" and gender .. "-" or ""
local plsuffix = args.n == "p" and "-p" or ""
local hgens
if args.a == "a" then
hgens = {gender .. "an" .. plsuffix}
elseif args.a == "i" then
hgens = {gender .. "in" .. plsuffix}
elseif args.a == "ai" then
hgens = {gender .. "an" .. plsuffix, gender .. "in" .. plsuffix}
else
hgens = {gender .. "in" .. plsuffix, gender .. "an" .. plsuffix}
end
-- Insert into list of genders
for _, hgen in ipairs(hgens) do
insert_if_not(args.genders, hgen)
end
end
function export.do_generate_forms(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SETS and JOINER, where ARG_SETS
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Gather arguments into a list of ARG_SET objects, containing (potentially)
-- elements 1, 2, 3, 4, corresponding to accent pattern, stem, declension
-- type, pl stem and coming from consecutive numbered parameters. Sets of
-- declension parameters are separated by the word "or".
local arg_sets = {}
-- Find maximum-numbered arg, allowing for holes
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Now gather the arguments.
local offset = 0
local arg_set = {}
for i=1,(max_arg + 1) do
local end_arg_set = false
local end_word = false -- FIXME, is this correct?
local word_joiner
if i == max_arg + 1 then
end_arg_set = true
end_word = true
word_joiner = {""}
elseif args[i] == "_" then
end_arg_set = true
end_word = true
word_joiner = {" "}
elseif args[i] == "-" then
end_arg_set = true
end_word = true
word_joiner = {"-"}
elseif args[i] and rfind(args[i], "^join:") then
end_arg_set = true
end_word = true
word_joiner = extract_word_joiner(args[i])
elseif args[i] == "or" then
end_arg_set = true
end
if end_arg_set then
table.insert(arg_sets, arg_set)
arg_set = {}
offset = i
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
else
-- If the first argument isn't stress, that means all arguments
-- have been shifted to the left one. We want to shift them
-- back to the right one, so we change the offset so that we
-- get the same effect of skipping a slot in the arg set.
if i - offset == 1 and not arg1_is_stress(args[i]) then
offset = offset - 1
end
if i - offset > 4 then
error("Too many arguments for argument set: arg " .. i .. " = " .. (args[i] or "(blank)"))
end
arg_set[i - offset] = args[i]
end
end
return generate_forms_1(args, per_word_info)
end
function export.do_generate_forms_multi(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SET and JOINER, where ARG_SET
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Find maximum-numbered arg, allowing for holes (FIXME: Is this needed
-- here? Will there be holes?)
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Gather arguments into a list of ARG_SET objects, containing
-- (potentially) elements 1, 2, 3, corresponding to accent pattern,
-- lemma+declension spec, pl stem, exactly as with do_generate_forms()
-- and {{ru-noun-table}} except that the values come from a single argument
-- of the form ACCENTPATTERN:LEMMADECL:PL where all but LEMMADECL may (and
-- probably will be) omitted and LEMMADECL may be of the following forms:
-- LEMMA (for a noun with empty decl spec),
-- LEMMADECL (for a noun with non-empty decl spec beginning with a
-- *, left paren or semicolon),
-- LEMMA^DECL (for a noun with non-empty decl spec),
-- LEMMA$ (for an indeclinable word)
-- LEMMA+ (for an adjective with auto-detected decl class)
-- LEMMA+DECL (for an adjective with explicit decl class)
-- Sets of parameters for the same word are separated by the word "or".
local arg_sets = {}
local continue_arg_sets = true
for i=1,(max_arg + 1) do
local end_word = false
local word_joiner
local process_arg = false
if i == max_arg + 1 then
end_word = true
word_joiner = {""}
elseif args[i] == "-" then
end_word = true
word_joiner = {"-"}
continue_arg_sets = true
elseif rfind(args[i], "^join:") then
end_word = true
word_joiner = extract_word_joiner(args[i])
continue_arg_sets = true
elseif args[i] == "or" then
continue_arg_sets = true
else
if continue_arg_sets then
continue_arg_sets = false
else
end_word = true
word_joiner = {" "}
end
process_arg = true
end
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
if process_arg then
local vals = rsplit(args[i], ":")
if #vals > 3 then
error("Can't specify more than 3 colon-separated params of param set: " .. args[i])
end
local arg_set = {}
if arg1_is_stress(vals[1]) then
arg_set[1] = vals[1]
arg_set[2] = vals[2]
arg_set[4] = vals[3]
else
arg_set[2] = vals[1]
arg_set[4] = vals[2]
end
-- recognize indeclinable
local indecl_stem = rmatch(arg_set[2], "^(.-)%$$")
if indecl_stem then
arg_set[2] = indecl_stem
arg_set[3] = "$"
else
-- recognize adjective
local adj_stem, adj_type = rmatch(arg_set[2], "^(.*)(%+.*)$")
if adj_stem then
arg_set[2] = adj_stem
arg_set[3] = adj_type
else
-- recognize noun with ^
local noun_stem, noun_type = rmatch(arg_set[2], "^(.*)%^(.*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- recognize noun without ^ but with decl spec
noun_stem, noun_type = rmatch(arg_set[2], "^(..-)([;*(].*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- noun without ^ or decl spec; nothing to do
end
end
end
end
table.insert(arg_sets, arg_set)
end
end
return generate_forms_1(args, per_word_info)
end
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence.
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence,
-- as well as show_z() for template {{ru-decl-noun-z}}, which has a
-- subset of the functionality of the other two.
generate_forms_1 = function(args, per_word_info)
local orig_args
if test_new_ru_noun_module then
orig_args = mw.clone(args)
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local old = args.old
local function verify_animacy_value(val)
if not val then return nil end
if val == "a" or val == "an" or val == "anim" then
return "a"
elseif val == "i" or val == "in" or val == "inan" then
return "i"
elseif val == "b" or val == "bi" or val == "both" or val == "ai" then
return "ai"
elseif val == "ia" then
return "ia"
end
error("Animacy value " .. val .. " should be empty or a/an/anim (animate), i/in/inan (inanimate), b/bi/both/ai (bianimate, listing animate first), or ia (bianimate, listing inanimate first)")
return nil
end
local function verify_number_value(val, allow_none)
if not val then return nil end
local short = usub(val, 1, 1)
if short == "s" or short == "p" or short == "b" or (allow_none and short == "n" or false) then
return short
end
if allow_none then
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), 'b' (both) or 'n' (none)")
else
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), or 'b' (both)")
end
return nil
end
-- Verify and canonicalize animacy, number, prefix, suffix
assert(#per_word_info >= 1)
for i=1,#per_word_info do
args["a" .. i] = verify_animacy_value(args["a" .. i])
args["n" .. i] = verify_number_value(args["n" .. i])
args["prefix" .. i] = com.split_russian_tr(args["prefix" .. i] or "", "dopair")
args["suffix" .. i] = com.split_russian_tr(args["suffix" .. i] or "", "dopair")
end
args.a = verify_animacy_value(args.a) or "i"
-- args.ndef, if set, is the default value for args.n; if unset, it defaults
-- to "both". It is set to "singular" in ru-proper noun+. We store the value
-- of args.n in args.orign before defaulting to args.ndef because we may
-- change it to plural-only later on if it was unspecified (this happens if
-- an individual word's lemma is plural), and to determine whether it was
-- unspecified, we need the original value before defaulting.
args.n = verify_number_value(args.n, "allow none")
-- treat n=none like n=sg but set a flag so "singular" isn't displayed
if args.n == "n" then
args.n = "s"
args.nonumber = true
end
args.ndef = verify_number_value(args.ndef)
args.orign = args.n
args.n = args.n or args.ndef
args.prefix = com.split_russian_tr(args.prefix or "", "dopair")
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
-- Attach overall prefix to first per-word prefix, similarly for suffix
args.prefix1 = com.concat_paired_russian_tr(args.prefix, args.prefix1)
args["suffix" .. #per_word_info] = com.concat_paired_russian_tr(
args["suffix" .. #per_word_info], args.suffix)
-- Initialize non-word-specific arguments.
--
-- The following is a list of WORD_INFO items, one per word, each of
-- which is a two element list of WORD_FORMS (a table listing the forms for
-- each case) and JOINER (a string, indicating how to join the word with
-- the next one).
args.per_word_info = {}
-- List of HEADING_INFO items, one per word, containing the raw material
-- used to generate the header. Initialized from 'args.heading_info',
-- which is initialized in categorize_and_init_heading().
args.per_word_heading_info = {}
-- List of CATEGORIES items, one per word, containing the categories
-- used to initialize the page categories. Initialized from
-- 'args.categories', which is initialized in categorize_and_init_heading().
args.per_word_categories = {}
-- List of HEADINGS items, one per word, containing the actual words that
-- go into the header if we were to use that word to construct the header.
-- Comes from compute_heading(). We use this to generate the actual header
-- string, which goes into 'args.heading' at the end (done in
-- compute_overall_heading_categories_and_genders()).
args.per_word_headings = {}
-- List of GENDERS items, one per word, containing the headword genders
-- for each word (where "headword gender" is in the format used in
-- headwords and actually includes animacy and number as well, e.g.
-- 'm-in' or 'f-an-p'). We end up selecting one such item and putting
-- it into 'args.genders' at the end
-- (in compute_overall_heading_categories_and_genders()).
args.per_word_genders = {}
args.any_overridden = {}
args.any_non_nil = {}
args.any_irreg = false
args.any_irreg_case = {}
local function insert_cat(cat)
insert_category(args.categories, cat, args.pos)
end
args.internal_notes = {}
local decl_sufs = old and declensions_old or declensions
local decl_cats = old and declensions_old_cat or declensions_cat
local intable = old and internal_notes_table_old or internal_notes_table
-- Default lemma defaults to previous lemma, first one to page name.
-- FIXME: With multiple words, we should probably split the page name
-- on spaces and default each word in turn
local default_lemma
local all_stresses_seen
-- Made into a function to avoid having to indent a lot of code.
-- Process a single arg set of a single word. This inserts the forms
-- for the word into args.forms and sets categories and tracking pages.
local function do_arg_set(arg_set, n, islast)
local stress_arg = arg_set[1]
local decl = arg_set[3] or ""
local pl, pltr
if arg_set[4] then
pl, pltr = com.split_russian_tr(arg_set[4])
end
-- Extract special markers from declension class.
if decl == "manual" then
decl = "$"
args.manual = true
if #per_word_info > 1 or #per_word_info[1][1] > 1 then
error("Can't specify multiple words or argument sets when manual")
end
if pl then
error("Can't specify optional stem parameters when manual")
end
end
decl, args.jo_special = rsubb(decl, "([^/%a])ё$", "%1")
if not args.jo_special then
decl, args.jo_special = rsubb(decl, "([^/%a])ё([^/%a])", "%1%2")
end
decl, args.want_sc1 = rsubb(decl, "%(1%)", "")
decl, args.alt_gen_pl = rsubb(decl, "%(2%)", "")
decl, args.reducible = rsubb(decl, "%*", "")
decl, args.soft_n = rsubb(decl, "%(нь%)", "")
decl = rsub(decl, ";", "")
-- Get the lemma.
local lemma = args.manual and "-" or arg_set[2] or default_lemma
if not lemma then
error("Lemma in first argument set must be specified")
end
default_lemma = lemma
local lemmatr
lemma, lemmatr = com.split_russian_tr(lemma)
-- If we're conjugating a suffix, insert a pseudoconsonant at the beginning
-- of all forms, so they get conjugated as if ending in a consonant.
-- We remove the pseudoconsonant later.
local is_suffix = lemma ~= "-" and rfind(lemma, "^%-")
args.any_suffix = args.any_suffix or is_suffix
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or is_suffix and PSEUDOCONS
if asif_prefix then
lemma = rsub(lemma, "^%-", "-" .. asif_prefix)
if lemmatr then
lemmatr = rsub(lemmatr, "^%-", "-" .. com.translit(asif_prefix))
end
end
args.thisa = args["a" .. n] or args.a
args.thisn = args["n" .. n] or args.n
-- Check for explicit allow-unaccented indication.
local allow_unaccented
lemma, allow_unaccented = rsubb(lemma, "^%*", "")
args.allow_unaccented = args.allow_unaccented or allow_unaccented
if args.allow_unaccented then
track("allow-unaccented")
end
args.orig_lemma = lemma
lemma = m_links.remove_links(lemma)
args.lemma_no_links = lemma
args.lemmatr = lemmatr
if args.lemma then
-- Explicit lemma given.
args.explicit_lemma, args.explicit_lemmatr = com.split_russian_tr(args.lemma)
end
-- Treat suffixes without an accent, and suffixes with an accent on the
-- initial hyphen, as if they were preceded with a *, which overrides
-- all the logic that normally (a) normalizes the accent, and (b)
-- complains about multisyllabic words without an accent. Don't do this
-- if lemma is just -, which is used specially in manual declension
-- tables (e.g. сто, три).
if lemma ~= "-" and (rfind(lemma, "^%-" .. AC) or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
-- Convert lemma and decl arg into stem and canonicalized decl.
-- This will autodetect the declension from the lemma if an explicit
-- decl isn't given.
local stem, tr, gender, was_accented, was_plural, was_autodetected
if rfind(decl, "^%+") then
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
detect_adj_type(lemma, lemmatr, decl, old)
else
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
determine_decl(lemma, lemmatr, decl, args)
end
if was_plural then
args.n = args.orign or "p"
args.thisn = args["n" .. n] or args.n
elseif decl ~= "$" then
args.thisn = args.thisn or "b"
end
args.explicit_gender = gender
-- If allow-unaccented not given, maybe check for missing accents.
if not args.allow_unaccented and not stress_arg and was_autodetected and com.needs_accents(lemma) then
-- If user gave the full word and expects us to determine the
-- declension and stress, the word should have an accent on the
-- stem or ending. We have a separate check farther below for
-- an accent on a multisyllabic stem, after stripping off any
-- ending; but this way we get an error if the user e.g. writes
-- "гора" without an accent rather than assuming it's stem
-- stressed, as would otherwise happen.
error("Lemma must have an accent in it: " .. lemma)
end
-- If stress not given, auto-determine; else validate/canonicalize
-- stress arg, override in certain cases and convert to list.
if not stress_arg then
stress_arg = {detect_stress_pattern(stem, decl, decl_cats, args.reducible, was_plural, was_accented)}
else
stress_arg = rsplit(stress_arg, ",")
for i=1,#stress_arg do
local stress = stress_arg[i]
stress = override_stress_pattern(decl, stress)
if not stress_patterns[stress] then
error("Unrecognized accent pattern " .. stress)
end
stress_arg[i] = stress
end
end
-- parse slash decl to list
local sub_decls
if rfind(decl, "/") then
track("mixed-decl")
insert_cat("~ with mixed declension")
local indiv_decls = rsplit(decl, "/")
-- Should have been caught in canonicalize_decl()
assert(#indiv_decls == 2)
sub_decls = {{indiv_decls[1], "sg"}, {indiv_decls[2], "pl"}}
else
sub_decls = {{decl}}
end
-- Get singular declension and corresponding category.
local sgdecl = sub_decls[1][1]
local sgdc = decl_cats[sgdecl]
assert(sgdc)
-- Compute headword gender(s). We base it off the singular declension
-- if we have a slash declension -- it's the best we can do.
determine_headword_gender(args, sgdc, gender)
local original_stem, original_tr = stem, tr
local original_pl, original_pltr = pl, pltr
-- Loop over accent patterns in case more than one given.
for _, stress in ipairs(stress_arg) do
args.suffixes = {}
stem, tr = original_stem, original_tr
local bare, baretr
local stem_for_bare, tr_for_bare
pl, pltr = original_pl, original_pltr
insert_if_not(all_stresses_seen, stress)
local stem_was_unstressed = com.is_unstressed(stem)
-- If special case ;ё was given and stem is unstressed,
-- add ё to the stem now; but don't let this interfere with
-- restressing, to handle cases like железа́ with gen pl желёз
-- but nom pl же́лезы.
if stem_was_unstressed and args.jo_special then
-- Beware, Cyrillic еЕ in first rsub, Latin eE in second
local new_stem = rsub(stem, "([еЕ])([^еЕ]*)$",
function(e, rest)
return (e == "Е" and "Ё" or "ё") .. rest
end
)
if stem == new_stem then
error("No е in stem to replace with ё")
end
stem = new_stem
if tr then
local subbed
-- e after j -> o, e not after j -> jo; don't just convert e -> jo
-- and then map jjo -> jo because we want to preserve double j
tr, subbed = rsubb(tr, "([jJ])([eE])([^eE]*)$",
function(j, e, rest)
return j .. (e == "E" and "O" or "o") .. AC .. rest
end
)
if not subbed then
tr = rsub(tr, "([eE])([^eE]*)$",
function(e, rest)
return (e == "E" and "Jo" or "jo") .. AC .. rest
end
)
end
tr = com.j_correction(tr)
end
-- This is used to handle железа́ with gen pl желёз and nom pl
-- же́лезы. We have two stressed stems, one for the gen pl and
-- one for the remaining pl cases, and the variable 'stem' can
-- handle only one, so we put the second (gen pl) stem in
-- stem_for_bare, which goes into the value of 'bare' (used
-- only for gen pl here).
stem_for_bare, tr_for_bare = stem, tr
end
-- Maybe add stress to the stem, depending on whether the
-- stem was unstressed and the stress pattern. Stem pattern f
-- and variants call for initial stress (голова́ -> го́ловы);
-- stem pattern d and variants call for stem-final stress
-- (сапожо́к -> сапо́жки). Stem patterns b and b' apparently
-- call for stem-final stress as well but it's unlikely to
-- make much of a difference (pattern b' only occurs in 3rd-decl
-- feminines, which should already have stress in the stem,
-- and the only place pattern b gets stem stress is in bare
-- forms, i.e. nom sg and/or gen pl depending on the decl type,
-- and nom sg stress should already be in the lemma while
-- gen pl stress is handled by a different ending-stressing
-- mechanism in attach_unstressed(); however, the user is
-- free to leave a masc or 3rd-decl fem lemma completely
-- unstressed with pattern b, and then the stem-final stress
-- *will* make a difference).
local function restress_stem(stem, tr, stress, stem_unstressed)
-- If the user has indicated they purposely are leaving the
-- word unstressed by putting a * at the beginning of the main
-- stem, leave it unstressed. This might indicate lack of
-- knowledge of the stress or a truly unaccented word
-- (e.g. an unaccented suffix).
if args.allow_unaccented then
return stem, tr
end
if tr and com.is_unstressed(stem) ~= com.is_unstressed(tr) then
error("Stem " .. stem .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(stem) then
stem, tr = com.make_ending_stressed(stem, tr)
-- For those patterns that are ending-stressed in the singular
-- nominative (and hence are likely to be expressed without an
-- accent on the stem) it's safe to put a particular accent on
-- the stem depending on the stress type. Otherwise, give an
-- error if no accent.
elseif stem_unstressed then
if rfind(stress, "^f") then
stem, tr = com.make_beginning_stressed(stem, tr)
elseif (rfind(stress, "^[bd]") or
args.thisn == "p" and ending_stressed_pl_patterns[stress]) then
stem, tr = com.make_ending_stressed(stem, tr)
elseif com.needs_accents(stem) then
error("Stem " .. stem .. " requires an accent")
end
end
return stem, tr
end
stem, tr = restress_stem(stem, tr, stress, stem_was_unstressed)
-- Leave pl unaccented if user wants this; see restress_stem().
if pl and not args.allow_unaccented then
if pltr and com.is_unstressed(pl) ~= com.is_unstressed(pltr) then
error("Plural stem " .. pl .. " and translit " .. pltr .. " must have same accent pattern")
end
if com.is_monosyllabic(pl) then
pl, pltr = com.make_ending_stressed(pl, pltr)
end
-- I think this is safe.
if com.needs_accents(pl) then
if ending_stressed_pl_patterns[stress] then
pl, pltr = com.make_ending_stressed(pl, pltr)
elseif not args.allow_unaccented then
error("Plural stem " .. pl .. " requires an accent")
end
end
end
local resolved_bare, resolved_baretr
-- Handle (de)reducibles
-- FIXME! We are dereducing based on the singular declension.
-- In a slash declension things can get weird and we don't
-- handle that. We are also computing the bare value from the
-- singular stem, and again things can get weird with a plural
-- stem. Note that we don't compute a bare value unless we have
-- to (either (de)reducible or stress pattern f/f'/f'' combined
-- with ё special case); the remaining times we generate the bare
-- value directly from the plural stem.
if args.reducible and not sgdc.ignore_reduce then
-- Zaliznyak treats all nouns in -ье and -ья as being
-- reducible. We handle this automatically and don't require
-- the user to specify this, but ignore it if so for
-- compatibility.
if is_reducible(sgdc) then
-- If we derived the stem from a nom pl form, then
-- it's already reduced, and we need to dereduce it to
-- get a bare form; otherwise the stem comes from the
-- nom sg and we need to reduce it to get the real stem.
if was_plural then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
resolved_bare, resolved_baretr = stem, tr
stem, tr = export.reduce_nom_sg_stem(stem, tr,
sgdecl, args.soft_n, "error")
-- Stem will be unstressed if stress was on elided
-- vowel; restress stem the way we did above. (This is
-- needed in at least one word, сапожо́к 3*d(2), with
-- plural stem probably сапо́жк- and gen pl probably
-- сапо́жек.)
stem, tr = restress_stem(stem, tr, stress,
com.is_unstressed(stem))
if stress ~= "a" and stress ~= "b" and args.alt_gen_pl and not pl then
-- Nouns like рожо́к, глазо́к of type 3*d(2) have
-- gen pl's ро́жек, гла́зок; to handle this,
-- dereduce the reduced stem and store in a
-- special place.
args.gen_pl_bare, args.gen_pl_baretr =
export.dereduce_nom_sg_stem(stem, tr,
sgdc, stress, old, "error")
end
end
elseif is_dereducible(sgdc) then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
error("Declension class " .. sgdecl .. " not (de)reducible")
end
elseif stem_for_bare and stem ~= stem_for_bare then
resolved_bare, resolved_baretr =
add_bare_suffix(stem_for_bare, tr_for_bare, old, sgdc, false)
end
-- Leave unaccented if user wants this; see restress_stem().
-- FIXME, we no longer allow the user to specify the bare value
-- so it's unclear if this is needed any more.
if resolved_bare and not args.allow_unaccented then
if resolved_baretr and com.is_unstressed(resolved_bare) ~= com.is_unstressed(resolved_baretr) then
error("Resolved bare stem " .. resolved_bare .. " and translit " .. resolved_baretr .. " must have same accent pattern")
end
if com.is_monosyllabic(resolved_bare) then
resolved_bare, resolved_baretr =
com.make_ending_stressed(resolved_bare, resolved_baretr)
else
if com.needs_accents(resolved_bare) then
error("Resolved bare stem " .. resolved_bare .. " requires an accent")
end
end
end
args.stem, args.stemtr = stem, tr
args.bare, args.baretr = resolved_bare, resolved_baretr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, tr)
if pl then
args.pl, args.pltr = pl, pltr
else
args.pl, args.pltr = stem, tr
end
args.upl, args.upltr = com.make_unstressed_once(args.pl, args.pltr)
-- Special hack for любо́вь and other reducible 3rd-fem nouns,
-- which have the full stem in the ins sg
args.ins_sg_stem = sgdecl == "ь-f" and args.reducible and resolved_bare
args.ins_sg_tr = sgdecl == "ь-f" and args.reducible and resolved_baretr
-- Loop over declension classes (we may have two of them, one for
-- singular and one for plural, in the case of a mixed declension
-- class of the form SGDECL/PLDECL).
for _,decl_spec in ipairs(sub_decls) do
local orig_decl = decl_spec[1]
local number = decl_spec[2]
local real_decl =
determine_stress_variant(orig_decl, stress)
real_decl = determine_stem_variant(real_decl,
number == "pl" and args.pl or args.stem)
-- sanity checking; errors should have been caught in
-- canonicalize_decl()
assert(decl_cats[real_decl], "real_decl " .. real_decl .. " nonexistent")
assert(decl_sufs[real_decl], "real_decl " .. real_decl .. " nonexistent")
tracking_code(stress, orig_decl, real_decl, args, n, islast)
do_stress_pattern(stress, args, real_decl, number, n, islast)
-- handle internal notes
local internal_note = intable[real_decl]
if internal_note then
insert_if_not(args.internal_notes, internal_note)
end
end
categorize_and_init_heading(stress, decl, args, n, islast)
end
end
local n = 0
for _, word_info in ipairs(per_word_info) do
n = n + 1
local islast = n == #per_word_info
local arg_sets, joiner = word_info[1], word_info[2]
args.forms = {}
args.heading_info = {animacy={}, number={}, gender={}, stress={},
stemetc={}, adjectival={}, reducible={}}
args.categories = {}
args.genders = {}
args.this_any_non_nil = {}
args.any_suffix = false
if #arg_sets > 1 then
track("multiple-arg-sets")
-- insert_cat("~ with multiple argument sets")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
default_lemma = pagename
all_stresses_seen = {}
-- Loop over all arg sets.
for _, arg_set in ipairs(arg_sets) do
do_arg_set(arg_set, n, islast)
end
if #all_stresses_seen > 1 then
track("multiple-accent-patterns")
-- insert_cat("~ with multiple accent patterns")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
table.insert(args.per_word_heading_info, args.heading_info)
table.insert(args.per_word_categories, args.categories)
local headings = compute_heading(args)
table.insert(args.per_word_headings, headings)
table.insert(args.per_word_genders, args.genders)
handle_forms_and_overrides(args, n, islast)
if args.any_suffix then
-- If we're conjugating a suffix, remove the pseudoconsonant or asif_prefix
-- that we previously inserted at the beginning.
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or PSEUDOCONS
local asif_prefix_tr = com.translit(asif_prefix)
for _, case in ipairs(all_cases) do
if args.forms[case] then
local newforms = {}
for _, form in ipairs(args.forms[case]) do
local formru = form[1]
local formtr = form[2]
formru = rsub(formru, "^%-" .. asif_prefix, "-")
if formtr then
formtr = rsub(formtr, "^%-" .. asif_prefix_tr, "-")
end
if formru == "-" then
-- if no ending, insert "(no suffix)".
table.insert(newforms, {"(no suffix)"})
else
table.insert(newforms, {formru, formtr})
end
end
args.forms[case] = newforms
end
end
end
table.insert(args.per_word_info, {args.forms, joiner})
end
handle_overall_forms_and_overrides(args)
compute_overall_heading_categories_and_genders(args)
for _, case in ipairs(all_cases) do
if args[case] then
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
ruentry = m_links.remove_links(ruentry)
if rfind(ulower(ruentry), latin_text_class) then
--error("Found Latin text " .. ruentry .. " in case " .. case)
track("latin-text")
track("latin-text/" .. case)
end
end
end
end
-- Test code to compare existing module to new one.
if test_new_ru_noun_module then
local m_new_ru_noun = require("Module:User:Benwing2/ru-noun")
local newargs = m_new_ru_noun.do_generate_forms(orig_args, old)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
local is_pl = rfind(case, "_pl")
if args.thisn == "s" and is_pl or args.thisn == "p" and not is_pl then
-- Don't need to check cases that won't be displayed.
elseif not m_table.deepEquals(arg, newarg) then
local monosyl_accent_diff = false
-- Differences only in monosyllabic accents. Enable if we
-- change the algorithm for these.
--if arg and newarg and #arg == 1 and #newarg == 1 then
-- local ru1, tr1 = arg[1][1], arg[1][2]
-- local ru2, tr2 = newarg[1][1], newarg[1][2]
-- if com.is_monosyllabic(ru1) and com.is_monosyllabic(ru2) then
-- ru1, tr1 = com.remove_accents(ru1, tr1)
-- ru2, tr2 = com.remove_accents(ru2, tr2)
-- if ru1 == ru2 and tr1 == tr2 then
-- monosyl_accent_diff = true
-- end
-- end
--end
if monosyl_accent_diff then
track("monosyl-accent-diff")
difdecl = true
else
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
end
if not difdecl then track("same-decl") end
end
return args
end
-- Implementation of main entry point
local function do_show(frame, old)
local args = clone_args(frame)
local args = export.do_generate_forms(args, old)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- Implementation of new entry point, esp. for multiple words
local function do_show_multi(frame)
local args = clone_args(frame)
local args = export.do_generate_forms_multi(args)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The new entry point, esp. for multiple words (but works fine for
-- single words).
function export.show_multi(frame)
return do_show_multi(frame)
end
local function get_form(forms, preserve_links, raw)
local canon_forms = {}
for _, form in ipairs(forms) do
if raw then
local ru, tr = form[1], form[2]
ru = rsub(ru, "|", "<!>")
if tr then
tr = rsub(tr, "|", "<!>")
end
insert_if_not(canon_forms, {ru, tr})
else
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
-- Skip hypothetical forms (but include in the raw versions)
if not rfind(runotes, HYPMARKER) then
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
end
if not preserve_links then
ruentry = m_links.remove_links(ruentry)
end
ruentry = rsub(ruentry, "|", "<!>")
if trentry then
trentry = rsub(trentry, "|", "<!>")
end
insert_if_not(canon_forms, {ruentry, trentry})
end
end
end
return com.concat_forms(canon_forms)
end
local function case_will_be_displayed(args, case)
local ispl = rfind(case, "_pl")
local caseok = true
if args.n == "p" then
caseok = ispl
elseif args.n == "s" then
caseok = not ispl
end
for _, override_case in ipairs(overridable_only_cases) do
if case == override_case and not args.any_overridden[override_case] then
caseok = false
break
end
end
if args.a == "a" or args.a == "i" then
if rfind(case, "_[ai]n") then
caseok = false
end
else -- bianimate
-- don't include inanimate/animate variants if combined variant exists
-- (typically because inanimate/animate variants are the same);
-- FIXME: This could conceivably be different from how the display
-- code works, which just checks that the inanimate/animate variants
-- are the same when deciding whether to display them, in particular
-- if there is an override. Here we are following the algorithm of
-- handle_overall_forms_and_overrides().
if (case == "acc_sg_in" or case == "acc_sg_an") and args.acc_sg or
(case == "acc_pl_in" or case == "acc_pl_an") and args.acc_pl then
caseok = false
end
end
if not args[case] then
caseok = false
end
return caseok
end
local function concat_case_args(args, do_all, raw)
local ins_text = {}
for _, case in ipairs(do_all and all_cases or overridable_cases) do
if case_will_be_displayed(args, case) then
local forms = get_form(args[case], rfind(case, "_linked"), raw)
if forms ~= "" then
table.insert(ins_text, case .. (raw and "_raw" or "") .. "=" ..
forms)
end
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-noun-forms' to generate all noun forms.
-- This returns a single string, with | separating arguments and named
-- arguments of the form NAME=VALUE.
function export.generate_forms(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
return concat_case_args(args)
end
-- The entry point to generate multiple sets of noun forms. This is a hack
-- to speed up calling from a bot, where we often want to compare old and new
-- argument results to make sure they're the same. Each set of arguments is
-- jammed together into a single argument with individual values separated by
-- <!>; named arguments are of the form NAME<->VALUE. The return value for
-- each set of arguments is as in export.generate_forms(), and the return
-- values are concatenated with <!> separating them. NOTE: This will fail if
-- the exact sequences <!> or <-> happen to occur in values (which is unlikely,
-- esp. as we don't even use the characters <, ! or > for anything) and aren't
-- HTML-escaped.
function export.generate_multi_forms(frame)
local retvals = {}
for _, argset in ipairs(frame.args) do
local args = {}
local i = 0
local argvals = rsplit(argset, "<!>")
for _, argval in ipairs(argvals) do
local split_arg = rsplit(argval, "<%->")
if #split_arg == 1 then
i = i + 1
args[i] = ine(split_arg[1])
else
assert(#split_arg == 2)
args[split_arg[1]] = ine(split_arg[2])
end
end
args = export.do_generate_forms(args, false)
table.insert(retvals, concat_case_args(args))
end
return table.concat(retvals, "<!>")
end
-- The entry point for 'ru-noun-form' to generate a particular noun form.
function export.generate_form(frame)
local args = clone_args(frame)
if not args.form then
error("Must specify desired form using form=")
end
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
local args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
-- The entry point for generating arguments of various sorts, including
-- the case forms, gender, number and animacy.
function export.generate_args(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
local retargs = {}
table.insert(retargs, concat_case_args(args, "doall"))
table.insert(retargs, concat_case_args(args, "doall", "raw"))
table.insert(retargs, "g=" .. table.concat(args.genders, ","))
-- The following is correct even with ndef because if ndef is
-- set we will set it in args.n.
table.insert(retargs, "n=" .. (args.n or "b"))
table.insert(retargs, "a=" .. (args.a or "i"))
return table.concat(retargs, "|")
end
-- The entry point for compatibility with {{ru-decl-noun-z}}.
function export.show_z(frame)
local args = clone_args(frame)
local stem = args[1]
local stress = args[2]
local specific = args[4] or ""
-- Parse gender/animacy spec
local gender, anim = rmatch(args[3], "^([mfn])-([a-z]+)")
if not gender then
error("Unrecognized gender/anim spec " .. args[3])
end
if anim ~= "an" and anim ~= "in" then anim = "both" end
args.a = anim
-- Handle specific
specific = rsub(specific, "ё", ";ё")
-- Compute decl; special case for семьянин (perhaps not necessary)
local decl = com.make_unstressed_once(stem) == "семьянин" and "#" .. specific or gender .. specific
-- Handle overrides
args.pre_sg = args.prp_sg
args.pre_pl = args.prp_pl
args.notes = args.note
if args.par then
args.par = "+"
end
if args.loc then
if args.loc == "в" then
args.loc = "в +"
elseif args.loc == "на" then
args.loc = "на +"
else
args.loc = "в +,на +"
end
end
local arg_set = {}
table.insert(arg_set, stress)
table.insert(arg_set, stem)
table.insert(arg_set, decl)
local per_word_info = {{{arg_set}, ""}}
return generate_forms_1(args, per_word_info)
end
--------------------------------------------------------------------------
-- Autodetection and lemma munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the stem and the ending. GENDER must be present with -ь and plural
-- stems, and is otherwise ignored. Return up to three values: The stem
-- (lemma minus ending), the singular lemma ending, and if the lemma was
-- plural, the plural lemma ending. If the lemma was singular, the singular
-- lemma ending will contain any user-given accents; likewise, if the
-- lemma was plural, the plural ending will contain such accents.
-- VARIANT comes from the declension spec and controls certain declension
-- variants.
local function detect_lemma_type(lemma, tr, gender, args, variant)
local base, ending = rmatch(lemma, "^(.*)([еЕ]" .. AC .. ")$") -- accented
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([еЕ])$") -- unaccented
if base then
if variant == "-ище" and not rfind(lemma, "[щЩ][еЕ]$") then
error("With declension variant -ище, lemma should end in -ще: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), variant == "-ище" and "(ищ)е-и" or "о"
end
if variant == "-ишко" then
base, ending = rmatch(lemma, "^(.*[шШ][кК])([оО])$") -- unaccented
if not base then
error("With declension variant -ишко, lemma should end in -шко: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), "(ишк)о-и"
end
if variant == "-ин" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$") -- maybe accented
if not base then
error("With declension variant -ин, lemma should end in -ин(ъ): " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
-- Now autodetect -ин; only animate and in -анин/-янин
base, ending = rmatch(lemma, "^(.*[аАяЯ][" .. AC .. GR .. "]?[нН])([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$")
-- Need to check the animacy to avoid nouns like маиганин, цианин,
-- меланин, соланин, etc.
if base and args.thisa == "a" then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([мМ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
--recognize plural endings
if gender == "n" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
-- Don't do this; о/-ья is too rare
-- error("Ambiguous plural lemma " .. lemma .. " in -ья, singular could be -о or -ье/-ьё; specify the singular")
return base, com.strip_tr_ending(tr, ending), "ье", ending
end
base, ending = rmatch(lemma, "^(.*)([аяАЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), rfind(ending, "[аА]") and "о" or "е", ending
end
base, ending = rmatch(lemma, "^(.*)([ыиЫИ][" .. AC .. GR .. "]?)$")
if base then
if rfind(ending, "[ыЫ]") or rfind(base, "[" .. com.sib .. com.velar .. "]$") then
return base, com.strip_tr_ending(tr, ending), "о-и", ending
else
-- FIXME, should we return a slash declension?
error("No neuter declension е-и available; use a slash declension")
end
end
end
if gender == "f" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ья", ending
end
end
-- Recognize masculines with irregular plurals, but only if the user
-- either explicitly specified that this noun is plural (n=p) or
-- specifically requested the irregular plural. This is necessary
-- because some masculine nouns have feminine endings, which look
-- like irregular plurals.
if gender == "m" then
if args.thisn == "p" or variant == "-ья" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-ья" or "-ья"), ending
end
end
if args.thisn == "p" or args.want_sc1 then
base, ending = rmatch(lemma, "^(.*)([аА][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-а" or "-а"), ending
end
base, ending = rmatch(lemma, "^(.*)([яЯ][" .. AC .. GR .. "]?)$")
if base then
if rfind(base, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return base, com.strip_tr_ending(tr, ending), "й-я", ending
else
return base, com.strip_tr_ending(tr, ending), "ь-я", ending
end
end
end
end
if gender == "m" or gender == "f" then
base, ending = rmatch(lemma, "^(.*[" .. com.sib .. com.velar .. "])([иИ][" .. AC .. GR .. "]?)$")
if not base then
base, ending = rmatch(lemma, "^(.*)([ыЫ][" .. AC .. GR .. "]?)$")
end
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and (args.old and "ъ" or "") or "а", ending
end
base, ending = rmatch(lemma, "^(.*[" .. com.vowel .. "й][" .. AC .. GR .. "]?)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "й" or "я", ending
end
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "ь-m" or "я", ending
end
end
if gender == "3f" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ь-f", ending
end
end
-- end of recognize-plurals code
base, ending = rmatch(lemma, "^(.*)([ьЬ][яеёЯЕЁ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([йаяеоёъЙАЯЕОЁЪ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ьЬ])$")
if base then
if gender == "m" or gender == "f" then
return base, com.strip_tr_ending(tr, ending), "ь-" .. gender
elseif gender == "3f" then
return base, com.strip_tr_ending(tr, ending), "ь-f"
else
error("Need to specify gender m or f with lemma in -ь: ".. lemma)
end
end
if rfind(lemma, "[ыиЫИ][" .. AC .. GR .. "]?$") then
error("If this is a plural lemma, gender must be specified: " .. lemma)
elseif rfind(lemma, "[иИіІуУыЫѣѢэЭюЮѵѴ]" .. DIA .. "?[" .. AC .. GR .. "]?$") then
error("Don't know how to decline lemma ending in this type of vowel: " .. lemma)
end
return lemma, tr, ""
end
local plural_variant_detection_map = {
[""] = {["-ья"]="-ья"},
["ъ"] = {["-ья"]="ъ-ья"},
}
local special_case_1_to_plural_variant = {
[""] = "-а",
["ъ"] = "ъ-а",
["й"] = "й-я",
["ь-m"] = "ь-я",
["о"] = "о-и",
-- these last two are here to avoid getting errors in that checks for
-- compatibility with special case 1; the basic variants of these decls
-- don't actually exist
["(ишк)о"] = "(ишк)о-и",
["(ищ)е"] = "(ищ)е-и",
}
local function map_decl(decl, fun)
if rfind(decl, "/") then
local split_decl = rsplit(decl, "/")
if #split_decl ~= 2 then
error("Mixed declensional class " .. decl
.. "needs exactly two classes, singular and plural")
end
return fun(split_decl[1]) .. "/" .. fun(split_decl[2])
else
return fun(decl)
end
end
-- Canonicalize decl class into non-accented and alias-resolved form;
-- but note that some canonical decl class names with an accent in them
-- (e.g. е́, not the same as е, whose accented version is ё; and various
-- adjective declensions).
local function canonicalize_decl(decl, old)
local function do_canon(decl)
-- remove accents, but not from е́ (for adj decls, accent matters
-- as well but we handle that by mapping the accent to a stress pattern
-- and then to the accented version in determine_stress_variant())
if decl ~= "е́" then
decl = com.remove_accents(decl)
end
local decl_aliases = old and declensions_old_aliases or declensions_aliases
local decl_cats = old and declensions_old_cat or declensions_cat
if decl_aliases[decl] then
-- If we find an alias, map it.
decl = decl_aliases[decl]
elseif not decl_cats[decl] then
error("Unrecognized declension class " .. decl)
end
return decl
end
return map_decl(decl, do_canon)
end
-- Attempt to determine the actual declension (including plural variants)
-- based on a combination of the declension the user specified, what can be
-- detected from the lemma, and special case (1), if given in the declension.
-- DECL is the value the user passed for the declension field, after
-- extraneous annotations (special cases (1) and (2), * for reducible,
-- ё for ё/ё alternation and a ; that may precede ё) have been stripped off.
-- What's left is one of the following:
--
-- 1. Blank, meaning to autodetect the declension from the lemma
-- 2. A hyphen followed by a declension variant (-ья, -ин, -ишко, -ище; see
-- long comment at top of file)
-- 3. A gender (m, f, n, 3f)
-- 4. A gender plus declension variant (e.g. f-ья)
-- 5. An actual declension, possibly including a plural variant (e.g. о-и) or
-- a slash declension (e.g. я/-ья, used for the noun дядя).
--
-- Return seven args: stem (lemma minus ending), translit, canonicalized
-- declension, explicitly specified gender if any (m, f, n or nil), whether
-- the specified declension or detected ending was accented, whether the
-- detected ending was pl, and whether the declension was autodetected
-- (corresponds to cases where a full word with ending attached is required
-- in the lemma field). "Canonicalized" means after autodetection, with
-- accents removed, with any aliases mapped to their canonical versions
-- and with any requested declension variants applied. The result is either a
-- declension that will have a categorization entry (in declensions_cat[] or
-- declensions_old_cat[]) or a slash declension where each part similarly has
-- a categorization entry.
--
-- Note that gender is never required when an explicit declension is given,
-- and in connection with stem autodetection is required only when the lemma
-- either ends in -ь or is plural.
determine_decl = function(lemma, tr, decl, args)
-- Assume we're passed a value for DECL of types 1-4 above, and
-- fetch gender and requested declension variant.
local stem
local want_ya_plural, orig_pl_ending, variant
local was_autodetected
local gender = rmatch(decl, "^(3?[mfn]?)$")
if not gender then
gender, variant = rmatch(decl, "^(3?[mfn]?)(%-[^%-]+)$")
-- But be careful with explicit declensions like -а that look like
-- variants without gender (FIXME, eventually we should maybe do
-- something about the potential ambiguity).
if gender == "" and not m_table.contains({"-ья", "-ин", "-ишко", "-ище"}, variant) then
gender, variant = nil, nil
end
end
-- If DECL is of type 1-4, handle declension variants and detect
-- the actual declension from the lemma.
if gender then
-- Check for declension variants
if variant then
if variant == "-ья" then
want_ya_plural = "-ья"
else
-- Sanity-check remaining declension variants, which need
-- specific values of animacy, gender and special-case (1)
local sc1_needed
local animate_needed
if variant == "-ишко" then
animate_needed = false
sc1_needed = true
elseif variant == "-ище" then
animate_needed = true
sc1_needed = true
elseif variant == "-ин" then
animate_needed = true
sc1_needed = false
else
-- WARNING: If adding another variant, you need to also
-- add to the list farther above.
error("Unrecognized declension variant " .. variant .. ", should be -ья, -ин, -ишко or -ище")
end
if sc1_needed and not args.want_sc1 then
error("Declension variant " .. variant .. " must be used with special case (1)")
elseif sc1_needed == false and args.want_sc1 then
error("Declension variant " .. variant .. " must not be used with special case (1)")
end
if animate_needed and args.thisa ~= "a" then
error("Declension variant " .. variant .. " must be specified as animate")
elseif animate_needed == false and args.thisa == "a" then
error("Declension variant " .. variant .. " must not be specified as animate")
end
if gender ~= "" and gender ~= "m" then
error("Declension variant " .. variant .. " should be used with the masculine gender")
end
end
end
stem, tr, decl, orig_pl_ending = detect_lemma_type(lemma, tr, gender,
args, variant)
was_autodetected = true
else
stem, tr = lemma, tr
end
-- Now canonicalize gender
if gender == "3f" then
gender = "f"
elseif gender == "" then
gender = nil
end
-- The ending should be treated as accented if either the original singular
-- or plural ending was accented, or if the stem is non-syllabic.
local was_accented = com.is_stressed(decl) or
orig_pl_ending and com.is_stressed(orig_pl_ending) or
com.is_nonsyllabic(stem)
local was_plural = not not orig_pl_ending
decl = canonicalize_decl(decl, args.old)
-- The rest of this code concerns plural variants. It's somewhat
-- complicated because there are potentially four sources of plural
-- variants (not to mention plural variants constructed using slash
-- notation):
--
-- 1. A user-requested plural variant in declension types 2 or 4 above
-- (currently only -ья)
-- 2. An explicit plural variant encoded in an explicit declension of
-- type 5 above
-- 3. An autodetected plural variant (which will happen in some cases
-- when autodetection is performed on a nominative plural)
-- 4. A plural variant derived using special case (1).
--
-- Up to three actual plural variants might exist (e.g. if the user
-- specifies a DECL value or 'm-ья(1)' and a STEM ending in -а,
-- although not all three can ever be compatible because -ья and (1)
-- are never compatible). We can't have all four because if there's
-- an explicit plural variant, there won't be a user-requested or
-- autodetected plural variant.
--
-- The goal below is to do two things: Check that all available plural
-- variants are the same, and generate the actual declension.
-- If we have a type-2 or type-3 variant, we already have the actual
-- declension; else we need to use a table to map the basic declension
-- to the one with the plural variant encoded in it.
--
-- NOTE: The code below was written with a more general plural-variant
-- system. It probably can be simplified a lot now.
-- 1: Handle explicit decl with slash variant
if rfind(decl, "/") then
if want_ya_plural then
-- Don't think this can happen
error("Plural variant " .. want_ya_plural .. " not compatible with slash declension " .. decl)
end
if args.want_sc1 then
error("Special case (1) not compatible with slash declension" .. decl)
end
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- 2: Retrieve explicitly specified or autodetected decl and pl. variant
local basic_decl, detected_or_explicit_plural = rmatch(decl, "^(.*)(%-[^mf]+)$")
if basic_decl == "ь" then
basic_decl = "ь-m"
end
basic_decl = basic_decl or decl
-- 3: Any user-requested plural variant must agree with explicit or
-- autodetected variant.
if want_ya_plural and detected_or_explicit_plural and want_ya_plural ~= detected_or_explicit_plural then
error("Plural variant " .. want_ya_plural .. " requested but plural variant " .. detected_or_explicit_plural .. " detected from plural stem")
end
-- 4: Handle special case (1). Derive the full declension, make sure its
-- plural variant matches any other available plural variants, and
-- return the declension.
if args.want_sc1 then
local sc1_decl = special_case_1_to_plural_variant[basic_decl] or
error("Special case (1) not compatible with declension " .. basic_decl)
local sc1_plural = rsub(sc1_decl, "^.*%-", "-")
local other_plural = want_ya_plural or detected_or_explicit_plural
if other_plural and sc1_plural ~= other_plural then
error("Plural variant " .. other_plural .. " specified or detected, but special case (1) calls for plural variant " .. sc1_plural)
end
return stem, tr, sc1_decl, gender, was_accented, was_plural, was_autodetected
end
-- 5: Handle user-requested plural variant without explicit or detected
-- one. (If an explicit or detected one exists, we've already checked
-- that it agrees with the user-requested one, and so we already have
-- our full declension.)
if want_ya_plural and not detected_or_explicit_plural then
local variant_decl
if plural_variant_detection_map[decl] then
variant_decl = plural_variant_detection_map[decl][want_ya_plural]
end
if variant_decl then
return stem, tr, variant_decl, gender, was_accented, was_plural, was_autodetected
else
return stem, tr, decl .. (args.old and "/ъ-ья" or "/-ья"), gender, was_accented, was_plural, was_autodetected
end
end
-- 6: Just return the full declension, which will include any available
-- plural variant in it.
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- Convert soft adjectival declensions into hard ones following certain
-- stem-final consonants. FIXME: We call this in two places, once
-- to handle auto-detection and once to handle explicit declensions; but
-- in the former case we end up calling it twice.
local function determine_adj_stem_variant(decl, stem)
local iend = rmatch(decl, "^%+[іи]([йея]?)$")
-- Convert ій/ий to ый after velar or sibilant. This is important for
-- velars; doesn't really matter one way or the other for sibilants as
-- the sibilant rules will convert both sets of endings to the same
-- thing (whereas there will be a difference with о vs. е for velars).
if iend and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl = "+ы" .. iend
-- The following is necessary for -ц, unclear if makes sense for
-- sibilants. (Would be necessary -- I think -- if we were
-- inferring short adjective forms, but we're not.)
elseif decl == "+ее" and rfind(stem, "[" .. com.sib_c .. "]$") then
decl = "+ое"
end
return decl
end
-- Attempt to determine the actual adjective declension based on a
-- combination of the declension the user specified and what can be detected
-- from the stem. DECL is the value the user passed for the declension field,
-- after extraneous annotations have been removed (although none are probably
-- relevant here). What's left is one of the following, which always begins
-- with +:
--
-- 1. +, meaning to autodetect the declension from the stem
-- 2. +ь, same as + but selects +ьий instead of +ий if lemma ends in -ий
-- 3. +short, +mixed or +proper, with the declension partly specified but
-- the particular gender/number-specific short/mixed variant to be
-- autodetected
-- 4. A gender (+m, +f or +n), used only for detecting the singular of
-- plural-form lemmas (this is primarily used in conjunction with template
-- ru-noun+, to explicitly specify the gender; for the actual declension,
-- it doesn't much matter what singular gender we pick since we're a
-- plural only)
-- 5. A gender plus short/mixed/proper/ь (e.g. +f-mixed), again with the gender
-- used only for detecting the singular of plural-form short/mixed lemmas
-- 6. An actual declension, possibly including a slash declension
-- (WARNING: Unclear if slash declensions will work, especially those
-- that are adjective/noun combinations)
--
-- Returns the same seven args as for determine_decl(). The returned
-- declension will always begin with +.
detect_adj_type = function(lemma, tr, decl, old)
local was_autodetected
local base, ending
local basedecl, g = rmatch(decl, "^(%+)([mfn])$")
if not basedecl then
g, basedecl = rmatch(decl, "^%+([mfn])%-([a-zь]+)$")
if basedecl then
basedecl = "+" .. basedecl
end
end
decl = basedecl or decl
if decl == "+" or decl == "+ь" then
local loc = rfind(lemma, "[аеиіоыя][" .. AC .. GR .. "]?[йея]$") or rfind(lemma, "ь[йея]$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
end
if ending == "ий" and decl == "+ь" then
decl = "+ьий"
elseif ending == "ій" and decl == "+ь" then
decl = "+ьій"
elseif ending then
decl = "+" .. ending
else
local loc, shortmixed = rfind(lemma, "[аоы][" .. AC .. GR .. "]?$") or rfind(lemma, "ъ?$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
shortmixed = rfind(base, "^[" .. com.uppercase .. "].*[иы]" .. AC .. "н$") and "stressed-proper" or -- accented
rfind(base, "^[" .. com.uppercase .. "].*[иы]н$") and "proper" or --not accented
rlfind(base, "[ёео][" .. AC .. GR .. "]?в$") and "short" or
rlfind(base, "[ыи]" .. AC .. "н$") and "stressed-short" or -- accented
rlfind(base, "[ыи]н$") and "mixed" --not accented
end
if not shortmixed then
error("Cannot determine stem type of adjective: " .. lemma)
end
decl = "+" .. ending .. "-" .. shortmixed
end
was_autodetected = true
elseif m_table.contains({"+short", "+mixed", "+proper"}, decl) then
base, ending = rmatch(lemma, "^(.-)([оаыъ]?[" .. AC .. GR .. "]?)$")
assert(base)
local shortmixed = usub(decl, 2)
if rlfind(base, "[ыи]" .. AC .. "н$") then -- accented
if shortmixed == "short" then shortmixed = "stressed-short"
elseif shortmixed == "proper" then shortmixed = "stressed-proper"
end
end
decl = "+" .. ending .. "-" .. shortmixed
was_autodetected = true
else
base = lemma
end
if ending and ending ~= "" then
tr = com.strip_tr_ending(tr, ending)
end
-- Remove any accents from the declension, but not their presence.
-- We will convert was_accented into stress pattern b, and convert that
-- back to an accented version in determine_stress_variant(). This way
-- we end up with the stressed version whether the user placed an accent
-- in the ending or decl or specified stress pattern b.
-- FIXME, might not work in the presence of slash declensions
local was_accented = com.is_stressed(decl)
decl = com.remove_accents(decl)
decl = map_decl(decl, function(decl)
return determine_adj_stem_variant(decl, base)
end)
local singdecl
if decl == "+ые" then
singdecl = (g == "m" or not g) and (was_accented and "+ой" or "+ый") or not old and g == "f" and "+ая" or not old and g == "n" and "+ое"
elseif decl == "+ыя" and old then
singdecl = (g == "f" or not g) and "+ая" or g == "n" and "+ое"
elseif decl == "+ие" and not old then
singdecl = (g == "m" or not g) and "+ий" or g == "f" and "+яя" or g == "n" and "+ее"
elseif decl == "+іе" and old and (g == "m" or not g) then
singdecl = "+ій"
elseif decl == "+ія" and old then
singdecl = (g == "f" or not g) and "+яя" or g == "n" and "+ее"
elseif decl == "+ьи" then
singdecl = (g == "m" or not g) and (old and "+ьій" or "+ьий") or g == "f" and "+ья" or g == "n" and "+ье"
elseif rfind(decl, "^%+ы%-") then -- decl +ы-mixed or similar
local beg = (g == "m" or not g) and (old and "ъ" or "") or g == "f" and "а" or g == "n" and "о"
singdecl = beg and "+" .. beg .. usub(decl, 3)
end
if singdecl then
was_plural = true
decl = singdecl
end
return base, tr, canonicalize_decl(decl, old), g, was_accented, was_plural, was_autodetected
end
-- If stress pattern omitted, detect it based on whether ending is stressed
-- or the decl class or stem accent calls for inherent stress, defaulting to
-- pattern a. This is run after alias resolution and accent removal of DECL;
-- WAS_ACCENTED indicates whether the ending was originally stressed.
-- FIXME: This is run before splitting slash patterns but should be run after.
detect_stress_pattern = function(stem, decl, decl_cats, reducible,
was_plural, was_accented)
-- ёнок and ёночек always bear stress
if rfind(decl, "ёнокъ?") or rfind(decl, "ёночекъ?") then
return "b"
-- stressed suffix и́н; missing in plural and true endings don't bear stress
-- (except for exceptional господи́н)
elseif rfind(decl, "инъ?") and was_accented then
return "d"
-- Adjectival -ой always bears the stress
elseif rfind(decl, "%+ой") then
return "b"
-- Adjectival stressed-short, stressed-proper bears the stress
elseif rfind(decl, "^%+.*%-stressed") then
return "b"
-- Pattern b if ending was accented by user
elseif was_accented then
return "b"
-- Nonsyllabic stem means pattern b
elseif com.is_nonsyllabic(stem) then
return "b"
-- Accent on reducible vowel in masc nom sg (not plural) means pattern b.
-- Think about whether we want to enable this.
-- elseif reducible and not was_plural then
-- -- FIXME hack. Eliminate plural part of slash declension.
-- decl = rsub(decl, "/.*", "")
-- if decl_cats[decl] and decl_cats[decl].g == "m" then
-- if com.is_ending_stressed(stem) or com.is_monosyllabic(stem) then
-- return "b"
-- end
-- end
end
return "a"
end
-- In certain special cases, depending on the declension, we override the
-- user-specified stress pattern and convert it to something else.
-- NOTE: This function is run after alias resolution and accent removal.
-- FIXME: It's also run before splitting slash patterns but should be run after.
override_stress_pattern = function(decl, stress)
-- ёнок and ёночек always bear stress; if user specified a,
-- convert to b. Don't do this with slash patterns (see FIXME above).
if stress == "a" and (rfind(decl, "^ёнокъ?$") or rfind(decl, "^ёночекъ?$")) then
return "b"
end
return stress
end
-- Canonicalize an adjectival declension to either the stressed or unstressed
-- variant depending on the stress. Ultimately this is what ensures that
-- the user's stress mark on an adjectival ending is respected.
determine_stress_variant = function(decl, stress)
if stress == "b" then
if decl == "+ая" then
return "+а́я"
elseif decl == "+ое" then
return "+о́е"
else
-- Convert +...-short to +...-stressed-short and same for -proper
local b, e = rmatch(decl, "^%+(.*)%-(short)$")
if not b then
b, e = rmatch(decl, "^%+(.*)%-(proper)$")
end
if b and not rfind(b, "%-stressed") then
return "+" .. b .. "-stressed-" .. e
end
end
end
return decl
end
-- Canonicalize a declension based on the final stem consonant, in
-- particular converting soft declensions to hard ones after velars and/or
-- sibilants. FIXME: We also do this canonicalization earlier on during
-- auto-detection (determine_adj_stem_variant() is called by
-- detect_adj_type(), and code in detect_lemma_type() does the equivalent
-- of the first clause below). Doing it here ensures that explicitly
-- specified declensions get handled as well, but it would be nice to not
-- do the same thing twice in the auto-detection case.
determine_stem_variant = function(decl, stem)
if decl == "е" and rfind(stem, "[" .. com.sib_c .. "]$") then
return "о"
end
return determine_adj_stem_variant(decl, stem)
end
is_reducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "3rd" and decl_cat.g == "f" or decl_cat.g == "m" then
return true
else
return false
end
end
-- Reduce nom sg to stem by eliminating the "epenthetic" vowel. Applies to
-- masculine 2nd-declension hard and soft, and 3rd-declension feminine in
-- -ь. STEM and DECL are after determine_decl(), before converting
-- outward-facing declensions to inward ones.
function export.reduce_nom_sg_stem(stem, tr, decl, soft_n, can_err)
local full_stem = stem .. (decl == "й" and decl or "")
local full_tr = tr and tr .. (decl == "й" and "j" or "")
local ret, rettr = com.reduce_stem(full_stem, full_tr, soft_n)
if not ret and can_err then
error("Unable to reduce stem " .. stem)
end
return ret, rettr
end
is_dereducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "1st" or decl_cat.decl == "2nd" and decl_cat.g == "n" then
return true
else
return false
end
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. dereducible nouns
-- in -ня.
add_bare_suffix = function(bare, baretr, old, sgdc, dereduced)
if old and sgdc.hard == "hard" then
-- Final -ъ isn't transliterated
return bare .. "ъ", baretr
elseif sgdc.hard == "soft" or sgdc.hard == "palatal" then
-- This next clause corresponds to a special case in Vitalik's module.
-- It says that nouns in -ня (accent class a) have gen pl without
-- trailing -ь. It appears to apply to most nouns in -ня (possibly
-- all in -льня), but ку́хня (gen pl ку́хонь) and дерéвня (gen pl
-- дереве́нь) is an exception. (Vitalik's module has an extra
-- condition here 'stress == "a"' that would exclude дере́вня but I
-- don't think this condition is in Zaliznyak, as he indicates
-- дере́вня as having an exceptional genitive plural.)
if dereduced and rfind(bare, "[нН]$") and sgdc.decl == "1st" then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
-- Final -ъ isn't transliterated
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return bare .. "й", baretr and (baretr .. "j")
else
return bare .. "ь", baretr and (baretr .. "ʹ")
end
else
return bare, baretr
end
end
-- Dereduce stem to the form found in the gen pl (and maybe nom sg) by
-- inserting an epenthetic vowel. Applies to 1st declension and 2nd
-- declension neuter, and to 2nd declension masculine when the stem was
-- specified as a plural form (in which case we're deriving the nom sg,
-- and also the gen pl in the alt-gen-pl scenario). STEM and DECL are
-- after determine_decl(), before converting outward-facing declensions
-- to inward ones. STRESS is the stess pattern.
function export.dereduce_nom_sg_stem(stem, tr, sgdc, stress, old, can_err)
local epenthetic_stress = ending_stressed_gen_pl_patterns[stress]
local ret, rettr = com.dereduce_stem(stem, tr, epenthetic_stress)
if not ret then
if can_err then
error("Unable to dereduce stem " .. stem)
else
return nil, nil
end
end
return add_bare_suffix(ret, rettr, old, sgdc, true)
end
--------------------------------------------------------------------------
-- Second-declension masculine --
--------------------------------------------------------------------------
----------------- Masculine hard -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style).
declensions_old["ъ"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and "е́й" or "о́въ"
end,
["alt_gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["ъ"] = { decl="2nd", hard="hard", g="m" }
-- Normal mapping of old ъ would be "" (blank), but we set up "#" as an alias
-- so we have a way of referring to it without defaulting if need be and
-- distinct from auto-detection (e.g. in the second stem of a word, or to
-- override autodetection of -ёнок or -ин -- the latter is necessary in the
-- case of семьянин).
declensions_aliases["#"] = ""
----------------- Masculine hard, irregular plural -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg nom pl -а.
declensions_old["ъ-а"] = mw.clone(declensions_old["ъ"])
declensions_old["ъ-а"]["nom_pl"] = "а́"
declensions_old_cat["ъ-а"] = { decl="2nd", hard="hard", g="m", alt_nom_pl=true }
declensions_aliases["#-a"] = "-a"
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg soft pl -ья.
-- Differs from the normal declension throughout the plural.
declensions_old["ъ-ья"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = "ьёвъ",
["alt_gen_pl"] = "е́й",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ъ-ья"] = { decl="2nd", hard="hard", g="m", irregpl=true }
declensions_aliases["#-ья"] = "-ья"
----------------- Masculine hard, suffixed, irregular plural -------------------
declensions_old["инъ"] = {
["nom_sg"] = "и́нъ",
["gen_sg"] = "и́на",
["dat_sg"] = "и́ну",
["acc_sg"] = nil,
["ins_sg"] = "и́номъ",
["pre_sg"] = "и́нѣ",
["nom_pl"] = "е́",
["gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["инъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old["ёнокъ"] = {
["nom_sg"] = "ёнокъ",
["gen_sg"] = "ёнка",
["dat_sg"] = "ёнку",
["acc_sg"] = nil,
["ins_sg"] = "ёнкомъ",
["pre_sg"] = "ёнкѣ",
["nom_pl"] = "я́та",
["gen_pl"] = "я́тъ",
["dat_pl"] = "я́тамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тами",
["pre_pl"] = "я́тахъ",
}
declensions_old_cat["ёнокъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["онокъ"] = "ёнокъ"
declensions_old_aliases["енокъ"] = "ёнокъ"
declensions_old["ёночекъ"] = {
["nom_sg"] = "ёночекъ",
["gen_sg"] = "ёночка",
["dat_sg"] = "ёночку",
["acc_sg"] = nil,
["ins_sg"] = "ёночкомъ",
["pre_sg"] = "ёночкѣ",
["nom_pl"] = "я́тки",
["gen_pl"] = "я́токъ",
["dat_pl"] = "я́ткамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тками",
["pre_pl"] = "я́ткахъ",
}
declensions_old_cat["ёночекъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["оночекъ"] = "ёночекъ"
declensions_old_aliases["еночекъ"] = "ёночекъ"
----------------- Masculine soft -------------------
-- Normal soft-masculine declension in -ь
declensions_old["ь-m"] = {
["nom_sg"] = "ь",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["alt_gen_pl"] = "ь",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-m"] = { decl="2nd", hard="soft", g="m" }
-- Soft-masculine declension in -ь with irreg nom pl -я
declensions_old["ь-я"] = mw.clone(declensions_old["ь-m"])
declensions_old["ь-я"]["nom_pl"] = "я́"
declensions_old_cat["ь-я"] = { decl="2nd", hard="soft", g="m", alt_nom_pl=true }
----------------- Masculine palatal -------------------
-- Masculine declension in palatal -й
declensions_old["й"] = {
["nom_sg"] = "й",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = "ёвъ",
["alt_gen_pl"] = "й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["й"] = { decl="2nd", hard="palatal", g="m" }
declensions_old["й-я"] = mw.clone(declensions_old["й"])
declensions_old["й-я"]["nom_pl"] = "я́"
declensions_old_cat["й-я"] = { decl="2nd", hard="palatal", g="m", alt_nom_pl=true }
--------------------------------------------------------------------------
-- First-declension feminine --
--------------------------------------------------------------------------
----------------- Feminine hard -------------------
-- Hard-feminine declension in -а
declensions_old["а"] = {
["nom_sg"] = "а́",
["gen_sg"] = "ы́",
["dat_sg"] = "ѣ́",
["acc_sg"] = "у́",
["ins_sg"] = {"о́й<insa>", "о́ю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["а"] = { decl="1st", hard="hard", g="f" }
----------------- Feminine soft -------------------
-- Soft-feminine declension in -я
declensions_old["я"] = {
["nom_sg"] = "я́",
["gen_sg"] = "и́",
["dat_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_dat_sg_patterns[stress] and "и" or "ѣ́"
end,
["acc_sg"] = "ю́",
["ins_sg"] = {"ёй<insa>", "ёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "]́?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["я"] = { decl="1st", hard="soft", g="f" }
-- Soft-feminine declension in -ья.
-- Almost like ь + -я endings except for genitive plural.
declensions_old["ья"] = {
["nom_sg"] = "ья́",
["gen_sg"] = "ьи́",
["dat_sg"] = "ьѣ́",
["acc_sg"] = "ью́",
["ins_sg"] = {"ьёй<insa>", "ьёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ьи́",
["gen_pl"] = function(stem, stress)
-- circumflex accent is a signal that forces stress, particularly
-- in accent pattern d/d'.
return (ending_stressed_gen_pl_patterns[stress] or stress == "d" or stress == "d'") and "е̂й" or "ий"
end,
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ья"] = {
decl="1st", hard="soft", g="f",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
--------------------------------------------------------------------------
-- Second-declension neuter --
--------------------------------------------------------------------------
----------------- Neuter hard -------------------
-- Normal hard-neuter declension in -о
declensions_old["о"] = {
["nom_sg"] = "о́",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "о́" or nil
end,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "а́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "о́въ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["о"] = { decl="2nd", hard="hard", g="n" }
-- Hard-neuter declension in -о with irreg nom pl -и
declensions_old["о-и"] = mw.clone(declensions_old["о"])
declensions_old["о-и"]["nom_pl"] = "ы́"
declensions_old_cat["о-и"] = { decl="2nd", hard="hard", g="n", alt_nom_pl=true }
declensions_old_aliases["о-ы"] = "о-и"
-- Masculine-gender neuter-form declension in -(ишк)о with irreg nom pl -и,
-- with colloquial feminine endings in some of the singular cases
-- (§5 p. 74 of Zaliznyak)
declensions_old["(ишк)о-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ишк)о-и"]["gen_sg"] = {"а́", "ы́1"}
declensions_old["(ишк)о-и"]["dat_sg"] = {"у́", "ѣ́1"}
declensions_old["(ишк)о-и"]["ins_sg"] = {"о́мъ", "о́й1"}
declensions_old_cat["(ишк)о-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ишк)о-и"] = "<sup>1</sup> Colloquial."
-- Masculine-gender animate neuter-form declension in -(ищ)е with irreg
-- nom pl -и, with colloquial feminine endings in some of the singular cases
-- (§4 p. 74 of Zaliznyak)
declensions_old["(ищ)е-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ищ)е-и"]["acc_sg"] = {"а́", "у́1"}
declensions_old["(ищ)е-и"]["gen_sg"] = {"а́", "ы́2"}
declensions_old["(ищ)е-и"]["dat_sg"] = {"у́", "ѣ́2"}
declensions_old["(ищ)е-и"]["ins_sg"] = {"о́мъ", "о́й2"}
declensions_old_cat["(ищ)е-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ищ)е-и"] = "<sup>1</sup> Colloquial.<br /><sup>2</sup> Less common, more colloquial."
----------------- Neuter soft -------------------
-- Soft-neuter declension in -е (stressed -ё)
declensions_old["е"] = {
["nom_sg"] = "ё",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ё" or nil
end,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е"] = {
singular = function(suffix)
if suffix == "ё" then
return "ending in -ё"
else
return {}
end
end,
decl="2nd", hard="soft", g="n", gensg=true
}
-- User-facing declension type "ё" = "е"
declensions_old_aliases["ё"] = "е"
-- Rare soft-neuter declension in stressed -е́ (e.g. муде́, бытие́)
declensions_old["е́"] = {
["nom_sg"] = "е́",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "е́" or nil
end,
["ins_sg"] = "е́мъ",
["pre_sg"] = function(stem, stress)
-- FIXME!!! Are we sure about this condition? This is what was
-- found in the old template, but the related -е declension has
-- -ие prep sg ending -(и)и only when *not* stressed.
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and "и́" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "й" or "е́й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е́"] = {
singular = "ending in stressed -е",
decl="2nd", hard="soft", g="n", gensg=true
}
-- Soft-neuter declension in unstressed -ье (stressed -ьё).
declensions_old["ье"] = {
["nom_sg"] = "ьё",
["gen_sg"] = "ья́",
["dat_sg"] = "ью́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ьё" or nil
end,
["ins_sg"] = "ьёмъ",
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and "е́й" or "ий"
end,
["alt_gen_pl"] = "ьёвъ",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ье"] = {
decl="2nd", hard="soft", g="n",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
declensions_old_aliases["ьё"] = "ье"
--------------------------------------------------------------------------
-- Third declension --
--------------------------------------------------------------------------
declensions_old["ь-f"] = {
["nom_sg"] = "ь",
["gen_sg"] = "и́",
["dat_sg"] = "и́",
["acc_sg"] = "ь",
["ins_sg"] = "ью́",
["pre_sg"] = "и́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-f"] = { decl="3rd", hard="soft", g="f" }
declensions_old["мя"] = {
["nom_sg"] = "мя",
["gen_sg"] = "мени",
["dat_sg"] = "мени",
["acc_sg"] = nil,
["ins_sg"] = "менемъ",
["pre_sg"] = "мени",
["nom_pl"] = "мена́",
["gen_pl"] = "мёнъ",
["dat_pl"] = "мена́мъ",
["acc_pl"] = nil,
["ins_pl"] = "мена́ми",
["pre_pl"] = "мена́хъ",
}
declensions_old_cat["мя"] = { decl="3rd", hard="soft", g="n", cant_reduce=true }
--------------------------------------------------------------------------
-- Indeclinable --
--------------------------------------------------------------------------
-- Indeclinable declension; no endings.
declensions_old["$"] = {
["nom_sg"] = "",
["gen_sg"] = "",
["dat_sg"] = "",
["acc_sg"] = nil,
["ins_sg"] = "",
["pre_sg"] = "",
["nom_pl"] = "",
["gen_pl"] = "",
["dat_pl"] = "",
["acc_pl"] = nil,
["ins_pl"] = "",
["pre_pl"] = "",
}
declensions_old_cat["$"] = { decl="indeclinable", hard="none", g="none" }
--------------------------------------------------------------------------
-- Adjectival --
--------------------------------------------------------------------------
-- This needs to be up here because it is called just below.
local function old_to_new(v)
v = rsub(v, "ъ$", "")
v = rsub(v, "^ъ", "")
v = rsub(v, "(%A)ъ", "%1")
v = rsub(v, "ъ(%A)", "%1")
v = rsub(v, "і", "и")
v = rsub(v, "ѣ", "е")
return v
end
-- Meaning of entry is:
-- 1. The declension name in module ru-adjective
-- 2. The masculine declension name in this module
-- 3. The neuter declension name in this module
-- 4. The feminine declension name in this module
-- 5. The value of hard= for the declensions_cat entry
-- 6. The value of decl= for the declensions_cat entry
-- 7. The value of possadj= for the declensions_cat entry (true if possessive
-- or similar type of adjective)
local adj_decl_map = {
{"ый", "ый", "ое", "ая", "hard", "long", false},
{"ій", "ій", "ее", "яя", "soft", "long", false},
{"ой", "ой", "о́е", "а́я", "hard", "long", false},
{"ьій", "ьій", "ье", "ья", "palatal", "long", true},
{"short", "ъ-short", "о-short", "а-short", "hard", "short", true},
{"mixed", "ъ-mixed", "о-mixed", "а-mixed", "hard", "mixed", true},
{"proper", "ъ-proper", "о-proper", "а-proper", "hard", "proper", true},
{"stressed-short", "ъ-stressed-short", "о-stressed-short", "а-stressed-short", "hard", "short", true},
{"stressed-proper", "ъ-stressed-proper", "о-stressed-proper", "а-stressed-proper", "hard", "proper", true},
}
local function get_adjectival_decl(adjtype, gender, old)
local decl, intnotes = m_ru_adj.get_nominal_decl(adjtype, gender, old)
-- hack fem ins_sg to insert <insa>, <insb>; see concat_word_forms_1()
if gender == "f" and type(decl["ins_sg"]) == "table" and #decl["ins_sg"] == 2 then
decl["ins_sg"][1] = decl["ins_sg"][1] .. "<insa>"
decl["ins_sg"][2] = decl["ins_sg"][2] .. "<insb>"
end
return decl, intnotes
end
for _, declspec in ipairs(adj_decl_map) do
local oadjdecl = declspec[1]
local nadjdecl = old_to_new(oadjdecl)
local odecl_by_gender =
{m="+" .. declspec[2], n="+" .. declspec[3], f="+" .. declspec[4]}
local hard = declspec[5]
local decltype = declspec[6]
local possadj = declspec[7]
for _, g in ipairs({"m", "n", "f"}) do
local odecl = odecl_by_gender[g]
local ndecl = old_to_new(odecl)
declensions_old[odecl], internal_notes_table_old[odecl] =
get_adjectival_decl(oadjdecl, g, true)
declensions[ndecl], internal_notes_table[ndecl] =
get_adjectival_decl(nadjdecl, g, false)
declensions_old_cat[odecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
declensions_cat[ndecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
end
end
-- Set up some aliases.
declensions_old_aliases["+о́-short"] = "+о-stressed-short"
declensions_old_aliases["+а́-short"] = "+а-stressed-short"
declensions_old_aliases["+о́-proper"] = "+о-stressed-proper"
declensions_old_aliases["+а́-proper"] = "+а-stressed-proper"
declensions_aliases["+#-short"] = "+-short"
declensions_aliases["+#-mixed"] = "+-mixed"
declensions_aliases["+#-proper"] = "+-proper"
declensions_aliases["+#-stressed-short"] = "+-stressed-short"
declensions_aliases["+#-stressed-proper"] = "+-stressed-proper"
--------------------------------------------------------------------------
-- Populate new from old --
--------------------------------------------------------------------------
-- Function to convert an entry in an old declensions table to new.
local function old_decl_entry_to_new(v)
if not v then
return nil
elseif type(v) == "table" then
local new_entry = {}
for _, i in ipairs(v) do
table.insert(new_entry, old_decl_entry_to_new(i))
end
return new_entry
elseif type(v) == "function" then
return function(stem, suffix, args)
return old_decl_entry_to_new(v(stem, suffix, args))
end
else
return old_to_new(v)
end
end
-- Function to convert an old declensions table to new.
local function old_decl_to_new(odecl)
local ndecl = {}
for k, v in pairs(odecl) do
ndecl[k] = old_decl_entry_to_new(v)
end
return ndecl
end
-- Function to convert an entry in an old declensions_cat table to new.
local function old_decl_cat_entry_to_new(odecl_cat_entry)
if not odecl_cat_entry then
return nil
elseif type(odecl_cat_entry) == "function" then
return function(suffix)
return old_decl_cat_entry_to_new(odecl_cat_entry(suffix))
end
elseif type(odecl_cat_entry) == "table" then
local ndecl_cat_entry = {}
for k, v in pairs(odecl_cat_entry) do
ndecl_cat_entry[k] = old_decl_cat_entry_to_new(v)
end
return ndecl_cat_entry
elseif type(odecl_cat_entry) == "boolean" then
return odecl_cat_entry
else
assert(type(odecl_cat_entry) == "string")
return old_to_new(odecl_cat_entry)
end
end
-- Function to convert an old declensions_cat table to new.
local function old_decl_cat_to_new(odeclcat)
local ndeclcat = {}
for k, v in pairs(odeclcat) do
ndeclcat[k] = old_decl_cat_entry_to_new(v)
end
return ndeclcat
end
-- populate declensions[] from declensions_old[]
for odecltype, odecl in pairs(declensions_old) do
local ndecltype = old_to_new(odecltype)
if not declensions[ndecltype] then
declensions[ndecltype] = old_decl_to_new(odecl)
end
end
-- populate declensions_cat[] from declensions_old_cat[]
for odecltype, odeclcat in pairs(declensions_old_cat) do
local ndecltype = old_to_new(odecltype)
if not declensions_cat[ndecltype] then
declensions_cat[ndecltype] = old_decl_cat_to_new(odeclcat)
end
end
-- populate declensions_aliases[] from declensions_old_aliases[]
for ofrom, oto in pairs(declensions_old_aliases) do
local from = old_to_new(ofrom)
if not declensions_aliases[from] then
declensions_aliases[from] = old_to_new(oto)
end
end
-- populate internal_notes_table[] from internal_notes_table_old[]
for odecl, note in pairs(internal_notes_table_old) do
local ndecl = old_to_new(odecl)
if not internal_notes_table[ndecl] then
-- FIXME, should we be calling old_to_new() here?
internal_notes_table[ndecl] = note
end
end
--------------------------------------------------------------------------
-- Inflection functions --
--------------------------------------------------------------------------
-- Attach the stressed stem (or plural stem, or barestem) out of ARGS
-- to the unstressed suffix SUF, modifying the suffix as necessary for the
-- last letter of the stem (e.g. if it is velar, sibilant or ц). CASE is
-- the case form being created and is used to select the plural stem if
-- needed. Returns two values, the combined form and the modified suffix.
local function attach_unstressed(args, case, suf, was_stressed)
if suf == nil then
return nil, nil
elseif rfind(suf, CFLEX) then -- if suf has circumflex accent, it forces stressed
return attach_stressed(args, case, suf)
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.pl, args.pltr
end
if not stem and case == "ins_sg" then
stem, tr = args.ins_sg_stem, args.ins_sg_tr
end
if not stem then
stem, tr = args.stem, args.stemtr
end
if nom.nonsyllabic_suffixes[suf] then
-- If gen_pl, use special args.gen_pl_bare if given, else regular
-- args.bare if there isn't a plural stem. If nom_sg, always use
-- regular args.bare.
local barearg, bareargtr
if case == "gen_pl" then
barearg, bareargtr = args.gen_pl_bare, args.gen_pl_baretr
if not barearg and args.pl == args.stem then
barearg, bareargtr = args.bare, args.baretr
end
else
barearg, bareargtr = args.bare, args.baretr
end
local barestem = barearg or stem
local barestem, baretr
if barearg then
barestem, baretr = barearg, bareargtr
else
barestem, baretr = stem, tr
end
if was_stressed and case == "gen_pl" then
if not barearg then
local gen_pl_stem, gen_pl_tr = com.make_ending_stressed(stem, tr)
barestem, baretr = gen_pl_stem, gen_pl_tr
end
end
if rlfind(barestem, "[йьъ]$") then
suf = ""
else
if suf == "ъ" then
-- OK
elseif suf == "й" or suf == "ь" then
if barearg and case == "gen_pl" then
-- explicit bare or reducible, don't add -ь
suf = ""
elseif rfind(barestem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
-- not reducible, do add -ь and correct to -й if necessary
suf = "й"
else
suf = "ь"
end
end
end
return com.concat_russian_tr(barestem, baretr, suf, nil, "dopair"), suf
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Analogous to attach_unstressed() but for the unstressed stem and a
-- stressed suffix.
attach_stressed = function(args, case, suf)
if suf == nil then
return nil, nil
end
-- circumflex forces stress even when the accent pattern calls for no stress
suf = rsub(suf, "̂", AC)
if com.is_unstressed(suf) then
return attach_unstressed(args, case, suf, "was stressed")
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.upl, args.upltr
end
if not stem then
stem, tr = args.ustem, args.ustemtr
end
local rules = nom.stressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Attach the appropriate stressed or unstressed stem (or plural stem as
-- determined by CASE, or barestem) out of ARGS to the suffix SUF, which may
-- be a list of alternative suffixes (e.g. in the inst sg of feminine nouns).
-- Calls FUN (either attach_stressed() or attach_unstressed()) to do the work
-- for an individual suffix. Returns two values, a list of combined forms
-- and a list of the real suffixes used (which may be modified from the
-- passed-in suffixes, e.g. by removing stress marks or modifying vowels in
-- various ways after a stem-final velar, sibilant or ц). Each combined form
-- is a two-element list {stem, tr} (or a one-element list if tr is nil).
-- IRREG is true if this is an irregular form. We are handling the Nth word;
-- ISLAST is true if this is the last one.
local function attach_with(args, case, suf, fun, irreg, n, islast)
if type(suf) == "table" then
local all_combineds = {}
local all_realsufs = {}
for _, x in ipairs(suf) do
local combineds, realsufs =
attach_with(args, case, x, fun, irreg, n, islast)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
for _, realsuf in ipairs(realsufs) do
table.insert(all_realsufs, realsuf)
end
end
return all_combineds, all_realsufs
else
local combined, realsuf = fun(args, case, suf)
local irregsuf = irreg and {IRREGMARKER} or {""}
return {combined and com.concat_paired_russian_tr(
com.concat_paired_russian_tr(args["prefix" .. n], combined),
com.concat_paired_russian_tr(args["suffix" .. n], irregsuf)) or nil},
{realsuf and realsuf .. args["suffix" .. n][1] or nil}
end
end
-- Generate the form(s) and suffix(es) for CASE according to the declension
-- table DECL, using the attachment function FUN (one of attach_stressed()
-- or attach_unstressed()). IS_SLASH is true if this is a slash declension
-- (different declensions for singular and plural). We are handling the Nth
-- word; ISLAST is true if this is the last one.
local function gen_form(args, decl, case, stress, fun, is_slash, n, islast)
local irreg = false
if not args.suffixes[case] then
args.suffixes[case] = {}
end
local decl_sufs = args.old and declensions_old or declensions
decl_sufs = decl_sufs[decl]
local suf = decl_sufs[case]
local decl_cats = args.old and declensions_old_cat or declensions_cat
local ispl = rfind(case, "_pl")
if ispl and (decl_cats[decl].irregpl or args.pl and args.pl ~= args.stem or is_slash) then
irreg = true
end
if case == "nom_pl" and decl_cats[decl].alt_nom_pl then
irreg = true
end
if type(suf) == "function" then
suf = suf(ispl and args.pl or args.stem, stress, args)
end
if case == "gen_pl" and args.alt_gen_pl then
suf = decl_sufs.alt_gen_pl
irreg = true
if not suf then
error("No alternative genitive plural available for this declension class")
end
end
local combineds, realsufs = attach_with(args, case, suf, fun, irreg, n, islast)
for _, realsuf in ipairs(realsufs) do
args.any_non_nil[case] = true
args.this_any_non_nil[case] = true
insert_if_not(args.suffixes[case], realsuf)
end
return combineds
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
}
do_stress_pattern = function(stress, args, decl, number, n, islast)
local f = {}
for _, case in ipairs(decl_cases) do
if not number or (number == "sg" and rfind(case, "_sg")) or
(number == "pl" and rfind(case, "_pl")) then
f[case] = gen_form(args, decl, case, stress,
attachers[stress_patterns[stress][case]], not not number,
n, islast)
-- Turn empty form lists into nil to facilitate computation of
-- animate/inanimate accusatives below
if f[case] and #f[case] == 0 then
f[case] = nil
end
-- Compute linked versions of potential lemma cases, for use
-- in the ru-noun+ headword. We substitute the original lemma
-- (before removing links) for forms that are the same as the
-- lemma, if the original lemma has links.
if f[case] and (case == "nom_sg" or case == "nom_pl") then
local linked_forms = {}
for _, form in ipairs(f[case]) do
-- Return true if FORM is "close enough" to LEMMA that we can substitute the
-- linked form of the lemma. Currently this means exactly the same except that
-- we ignore acute and grave accent differences in monosyllables, and ignore
-- notes that may have been appended (e.g. the triangle marking irregularity).
local entry, notes = m_table_tools.separate_notes(form[1])
local lemma = args.lemma_no_links
local close_enough_to_lemma =
entry == lemma or (com.is_monosyllabic(entry) and
com.is_monosyllabic(lemma) and
com.remove_accents(entry) == com.remove_accents(lemma))
if close_enough_to_lemma and
rfind(args.orig_lemma, "%[%[") then
table.insert(linked_forms, {args.orig_lemma .. notes, args.lemmatr and args.lemmatr .. notes})
else
table.insert(linked_forms, form)
end
end
f[case .. "_linked"] = linked_forms
end
end
end
-- Set acc an/in variants now as appropriate. We used to do this in
-- handle_forms_and_overrides(), which simplified the handling of
-- nom/gen/acc overrides but caused problems for words like мазло and
-- трепло that had a mixture of nil and non-nil accusative forms.
local an = args.thisa
if not number or number == "sg" then
f.acc_sg_an = f.acc_sg_an or f.acc_sg or an == "i" and f.nom_sg or f.gen_sg
f.acc_sg_in = f.acc_sg_in or f.acc_sg or an == "a" and f.gen_sg or f.nom_sg
end
if not number or number == "pl" then
f.acc_pl_an = f.acc_pl_an or f.acc_pl or an == "i" and f.nom_pl or f.gen_pl
f.acc_pl_in = f.acc_pl_in or f.acc_pl or an == "a" and f.gen_pl or f.nom_pl
end
for case, forms in pairs(f) do
if not args.forms[case] then
args.forms[case] = {}
end
for _, form in ipairs(forms) do
insert_if_not(args.forms[case], form)
end
end
end
stress_patterns["a"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["b"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["b'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["c"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["d"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["d'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["e"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f''"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
ending_stressed_gen_pl_patterns = m_table.listToSet({"b", "b'", "c", "e", "f", "f'", "f''"})
ending_stressed_pre_sg_patterns = m_table.listToSet({"b", "b'", "d", "d'", "f", "f'", "f''"})
ending_stressed_dat_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_pl_patterns = m_table.listToSet({"b", "b'", "c"})
local numbers = {
["s"] = "singular",
["p"] = "plural",
}
local old_title_temp = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local title_temp = [=[Declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local extra_case_template, extra_case_template_with_plural
local internal_notes_template
local notes_template
local templates = {}
-- Convert a raw override into a canonicalized list of individual overrides.
-- If input is nil, so is output. Certain junk (e.g. <br/>) is removed,
-- and ~ and ~~ are substituted appropriately; ARGS and CASE are required for
-- this purpose. FORMS is the list of existing case forms and is currently
-- used only to retrieve the dat_sg for handling + in loc/par (this means
-- that any overrides of the dat_sg have to be handled before handling
-- overrides of loc/par). N is the suffix used to retrieve the override --
-- either a number for word-specific overrides, or an empty string for
-- overall overrides.
--
-- It will still be necessary to call m_table_tools.separate_notes() to separate
-- off any trailing "notes" (asterisks, superscript numbers, etc.), and
-- m_links.remove_links() to remove any links to get the raw override form.
canonicalize_override = function(args, case, forms, n)
local val = args[case .. n]
if not val then
return nil
end
-- clean <br /> that's in many multi-form entries and messes up linking
val = rsub(val, "<br%s*/>", "")
-- substitute ~ and ~~ and split by commas
local stem, manualtr
if rfind(case, "_pl") then
stem, manualtr = args.pl, args.pltr
end
if not stem then
stem, manualtr = args.stem, args.stemtr
end
local ustem, umanualtr = com.make_unstressed_once(stem, manualtr)
local stemtr, ustemtr = manualtr, umanualtr
local vals = rsplit(val, "%s*,%s*")
local retvals = {}
for _, val in ipairs(vals) do
local valru, valtr = com.split_russian_tr(val)
valru = rsub(valru, "~~", ustem)
valru = rsub(valru, "~", com.is_stressed(val) and ustem or stem)
if rfind(valru, "^%*") then
valru = rsub(valru, "^%*", "") .. HYPMARKER
end
if valtr then
stemtr = stemtr or com.translit_no_links(stem)
ustemtr = ustemtr or com.translit_no_links(ustem)
valtr = rsub(valtr, "~~", ustemtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and ustemtr or stemtr)
elseif val:find("~") and manualtr then
valtr = com.translit_no_links(val)
valtr = rsub(valtr, "~~", umanualtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and umanualtr or manualtr)
end
if valtr then
if valtr:sub(1, 1) == "*" then
valtr = valtr:sub(2) .. HYPMARKER
end
valtr = com.j_correction(valtr)
end
table.insert(retvals, {valru, valtr})
end
vals = retvals
-- handle + in loc/par meaning "the expected form"; NOTE: This requires
-- that dat_sg has already been processed!
if case == "loc" or case == "par" then
local new_vals = {}
for _, rutr in ipairs(vals) do
-- don't just handle + by itself in case the arg has в or на
-- or whatever attached to it
if rfind(rutr[1], "^%+") or rfind(rutr[1], "[%s%[|]%+") then
for _, dat in ipairs(forms["dat_sg"]) do
local ru, tr = rutr[1], rutr[2]
local datru, dattr = dat[1], dat[2]
local valru, valtr
-- separate off any footnote symbols (which may have been
-- introduced by a *tail or *tailall argument, which we need
-- to process before this stage so overrides don't get
-- automatically marked with footnote symbols); if par,
-- try to preserve them, but with loc this can cause
-- problems in case there are multiple dative forms
-- (stress variants) and the last one is marked with a
-- footnote symbol (occurs in грудь)
local datru_entry, datru_notes = m_table_tools.separate_notes(datru)
local dattr_entry, dattr_notes
if dattr then
dattr_entry, dattr_notes = m_table_tools.separate_notes(dattr)
end
if case == "par" then
valru, valtr = datru_entry, dattr_entry
else
valru, valtr = com.make_ending_stressed(datru_entry, dattr_entry)
datru_notes = ""
dattr_notes = ""
end
-- wrap the word in brackets so it's linked; but not if it
-- appears to already be linked
ru = rsub(ru, "^%+", "[[" .. valru .. "]]")
ru = rsub(ru, "([%[|])%+", "%1" .. valru)
ru = rsub(ru, "(%s)%+", "%1[[" .. valru .. "]]")
ru = ru .. datru_notes
-- do the translit; but it shouldn't have brackets in it
if tr or valtr then
tr = tr or com.translit_no_links(rutr[1])
valtr = valtr or com.translit_no_links(valru)
tr = rsub(tr, "^%+", valtr)
tr = rsub(tr, "(%s)%+", "%1" .. valtr)
tr = tr .. dattr_notes
end
table.insert(new_vals, {ru, tr})
end
else
table.insert(new_vals, rutr)
end
end
vals = new_vals
end
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(vals) do
local ru, tr = v[1], v[2]
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. n .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
vals = newvals
return vals
end
local function process_overrides(args, f, n)
local function process_override(case)
if args[case .. n] then
local overrides = canonicalize_override(args, case, f, n)
if not f[case] then
f[case] = {}
end
local new_overrides = {}
for _, form in ipairs(overrides) do
-- Don't consider overrides of loc/par/voc irregular since
-- they're only specified through overrides; FIXME: Theoretically
-- we could consider loc/par irregular if they don't follow the
-- expected forms; but we'd have to figure out how to eliminate
-- the preposition that may be specified
if not overridable_only_cases_set[case] and
not args.manual and
not contains_rutr_pair(f[case], form) then
local formru, formnotes = m_table_tools.separate_notes(form[1])
if formru ~= "-" then
-- don't mark an override of - as irregular, even if
-- it has an attached footnote symbol
form = com.concat_paired_russian_tr(form, {IRREGMARKER})
end
end
if case == "pauc" then
-- Internal note indicating that the form is for numbers 2, 3 and 4.
form = com.concat_paired_russian_tr(form, {paucal_marker})
end
table.insert(new_overrides, form)
end
f[case] = new_overrides
args.any_overridden[case] = true
end
end
-- do dative singular first because it will be used by loc/par
process_override("dat_sg")
-- now do the rest
for _, case in ipairs(overridable_cases) do
if case ~= "dat_sg" then
process_override(case)
end
end
-- if the nominative is overridden, use it to set the linked version unless
-- that is also specifically overridden
if args["nom_sg" .. n] and not args["nom_sg_linked" .. n] then
f.nom_sg_linked = f.nom_sg
end
if args["nom_pl" .. n] and not args["nom_pl_linked" .. n] then
f.nom_pl_linked = f.nom_pl
end
-- convert empty lists to nil to facilitate computation of accusative
-- case variants below.
for _, case in ipairs(all_cases) do
if f[case] then
if type(f[case]) ~= "table" then
error("Logic error, args[case] should be nil or table")
end
if #f[case] == 0 then
f[case] = nil
end
end
end
end
local function process_tail_args(args, f, n)
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function handle_tail_hyp(suf)
local arg, val
for _, case in ipairs(all_cases) do
arg = args[case .. "_" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args[case .. "_" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
if not rfind(case, "_pl") then
arg = args["sg" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["sg" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
else
arg = args["pl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["pl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
if not rfind(case, "nom_") and not rfind(case, "acc_") then
arg = args["obl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["obl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
end
end
handle_tail_hyp("tail")
handle_tail_hyp("hyp")
end
handle_forms_and_overrides = function(args, n, islast)
local f = args.forms
process_tail_args(args, f, n)
process_overrides(args, f, n)
local an = args.thisa
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). This logic duplicates logic in handle_overall_forms_and_overrides();
-- see long comment there. We need to duplicate the whole logic here to
-- handle words like мать-одиночка, which has an override of acc_sg1.
if not args["acc_sg_an" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_an = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_an = f.acc_sg or an == "i" and f.nom_sg or f.gen_sg or f.acc_sg_an
end
end
if not args["acc_sg_in" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_in = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_in = f.acc_sg or an == "a" and f.gen_sg or f.nom_sg or f.acc_sg_in
end
end
if not args["acc_pl_an" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_an = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_an = f.acc_pl or an== "i" and f.nom_pl or f.gen_pl or f.acc_pl_an
end
end
if not args["acc_pl_in" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_in = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_in = f.acc_pl or an == "a" and f.gen_pl or f.nom_pl or f.acc_pl_in
end
end
f.loc = f.loc or f.pre_sg
f.par = f.par or f.gen_sg
f.voc = f.voc or f.nom_sg
-- Set these in case we have plural only, in which case the
-- singular will also get set to these same values in case we are
-- a plural-only word in a singular-only expression.
f.loc_pl = f.loc_pl or f.pre_pl
f.par_pl = f.par_pl or f.gen_pl
f.voc_pl = f.voc_pl or f.nom_pl
f.count = f.count or f.gen_pl
f.pauc = f.pauc or f.gen_sg
local nu = args.thisn
-- If we have a singular-only, set the plural forms to the singular forms,
-- and vice-versa. This is important so that things work in multi-word
-- expressions that combine different number restrictions (e.g.
-- singular-only with singular/plural or singular-only with plural-only,
-- compare "St. Vincent and the Grenadines" [Сент-Винсент и Гренадины]).
if nu == "s" then
f.nom_pl_linked = f.nom_sg_linked
f.nom_pl = f.nom_sg
f.gen_pl = f.gen_sg
f.dat_pl = f.dat_sg
f.acc_pl = f.acc_sg
f.acc_pl_an = f.acc_sg_an
f.acc_pl_in = f.acc_sg_in
f.ins_pl = f.ins_sg
f.pre_pl = f.pre_sg
f.nom_pl = f.nom_sg
f.loc_pl = f.loc
f.par_pl = f.par
f.voc_pl = f.voc
elseif nu == "p" then
f.nom_sg_linked = f.nom_pl_linked
f.nom_sg = f.nom_pl
f.gen_sg = f.gen_pl
f.dat_sg = f.dat_pl
f.acc_sg = f.acc_pl
f.acc_sg_an = f.acc_pl_an
f.acc_sg_in = f.acc_pl_in
f.ins_sg = f.ins_pl
f.pre_sg = f.pre_pl
f.nom_sg = f.nom_pl
f.loc = f.loc_pl
f.par = f.par_pl
f.voc = f.voc_pl
end
end
handle_overall_forms_and_overrides = function(args)
local overall_forms = {}
for _, case in ipairs(displayable_cases) do
overall_forms[case] = concat_word_forms(args.per_word_info, case)
end
local acc_sg_overridden = args.acc_sg
local acc_pl_overridden = args.acc_pl
process_tail_args(args, overall_forms, "")
process_overrides(args, overall_forms, "")
if case_will_be_displayed(args, "pauc") then
insert_if_not(args.internal_notes, paucal_internal_note)
end
-- if IRREGMARKER is anywhere in text, remove all instances and put
-- at the end before any notes.
local function clean_irreg_marker(case, text)
if rfind(text, IRREGMARKER) then
text = rsub(text, IRREGMARKER, "")
local entry, notes = m_table_tools.separate_notes(text)
if case_will_be_displayed(args, case) then
insert_if_not(args.internal_notes, IRREGMARKER .. " Irregular.")
args.any_irreg = true
args.any_irreg_case[case] = true
end
return entry .. IRREGMARKER .. notes
else
return text
end
end
-- set final args[case] and clean up IRREGMARKER.
for _, case in ipairs(all_cases) do
args[case] = overall_forms[case]
if args[case] then
local cleaned_forms = {}
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
ru = clean_irreg_marker(case, ru)
if tr then
tr = clean_irreg_marker(case, tr)
end
table.insert(cleaned_forms, {ru, tr})
end
args[case] = cleaned_forms
end
end
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). We need to do this somewhat complicated procedure to get overrides
-- to work correctly, e.g. acc_sg overrides of feminine and neuter nouns
-- (such as мать and полслова) and gen_sg/gen_pl overrides of masculine
-- animate nouns. We also ran into an issue with words like мазло that are
-- neuter-form but can be both masculine animate (in which case the
-- acc sg inherits from the genitive) and neuter animate (in which case the
-- acc sg has the fixed ending -о, same as nominative, despite the animacy).
-- Remember also that the animate/inanimate accusative variants are the ones
-- displayed, not the plain acc_sg/acc_pl ones.
if not args.any_overridden.acc_sg_an then
if acc_sg_overridden then
args.acc_sg_an = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_an = args.acc_sg or args.a == "i" and args.nom_sg or args.gen_sg or args.acc_sg_an
end
end
if not args.any_overridden.acc_sg_in then
if acc_sg_overridden then
args.acc_sg_in = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_in = args.acc_sg or args.a == "a" and args.gen_sg or args.nom_sg or args.acc_sg_in
end
end
if not args.any_overridden.acc_pl_an then
if acc_pl_overridden then
args.acc_pl_an = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_an = args.acc_pl or args.a == "i" and args.nom_pl or args.gen_pl or args.acc_pl_an
end
end
if not args.any_overridden.acc_pl_in then
if acc_pl_overridden then
args.acc_pl_in = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_in = args.acc_pl or args.a == "a" and args.gen_pl or args.nom_pl or args.acc_pl_in
end
end
-- Try to set the values of acc_sg and acc_pl. The only time we can't is
-- when the noun is bianimate and the anim/inan values are different.
-- This is used primarily for generate_forms() and generate_multi_forms(),
-- since we don't actually display these forms.
if args.a == "a" then
args.acc_sg = args.acc_sg or args.acc_sg_an
args.acc_pl = args.acc_pl or args.acc_pl_an
elseif args.a == "i" then
args.acc_sg = args.acc_sg or args.acc_sg_in
args.acc_pl = args.acc_pl or args.acc_pl_in
else -- bianimate
args.acc_sg = args.acc_sg or m_table.deepEquals(args.acc_sg_in, args.acc_sg_an) and args.acc_sg_in or nil
args.acc_pl = args.acc_pl or m_table.deepEquals(args.acc_pl_in, args.acc_pl_an) and args.acc_pl_in or nil
end
end
-- Subfunction of concat_word_forms(), used to implement recursively
-- generating all combinations of elements from WORD_FORMS (a list, one
-- element per word, of a list of the forms for a word, each of which is a
-- two-element list of {RUSSIAN, TR}) and TRAILING_FORMS (a list of forms, the
-- accumulated suffixes for trailing words so far in the recursion process,
-- again where each form is a two-element list {RUSSIAN, TR}). Each time we
-- recur we take the last FORMS item off of WORD_FORMS and to each form in
-- FORMS we add all elements in TRAILING_FORMS, passing the newly generated
-- list of items down the next recursion level with the shorter WORD_FORMS.
-- We end up returning a list of concatenated forms, where each list item
-- is a two-element list {RUSSIAN, TR}.
local function concat_word_forms_1(word_forms, trailing_forms)
if #word_forms == 0 then
local retforms = {}
for _, form in ipairs(trailing_forms) do
local ru, tr = form[1], form[2]
-- Remove <insa> and <insb> markers; they've served their purpose.
ru = rsub(ru, "<ins[ab]>", "")
tr = tr and rsub(tr, "<ins[ab]>", "")
table.insert(retforms, {ru, tr})
end
return retforms
else
local last_form_info = table.remove(word_forms)
local last_forms, joiner = last_form_info[1], last_form_info[2]
local new_trailing_forms = {}
for _, form in ipairs(last_forms) do
for _, trailing_form in ipairs(trailing_forms) do
-- If form to prepend is empty, don't add the joiner; this
-- is principally used in overall overrides, where we stuff
-- the entire override into the last word
local full_form = form[1] == "" and trailing_form or
com.concat_paired_russian_tr(form,
com.concat_paired_russian_tr(joiner, trailing_form),
"movenotes")
if rfind(full_form[1], "<insa>") and rfind(full_form[1], "<insb>") then
-- REJECT! So we don't get mixtures of the two feminine
-- instrumental singular endings.
else
table.insert(new_trailing_forms, full_form)
end
end
end
return concat_word_forms_1(word_forms, new_trailing_forms)
end
end
-- Generate a list of overall forms by concatenating the per-word forms.
-- PER_WORD_INFO comes from args.per_word_info and is a list of
-- WORD_INFO items, one per word, each of which a two element list of
-- WORD_FORMS (a table listing the forms for each case) and JOINER (a string).
-- We loop over all possible combinations of elements from each word's list
-- of forms for the given case; this requires recursion.
concat_word_forms = function(per_word_info, case)
local word_forms = {}
-- Gather the appropriate word forms. We have to recreate this anew
-- because it will be destructively modified by concat_word_forms_1().
for _, word_info in ipairs(per_word_info) do
table.insert(word_forms, {word_info[1][case], word_info[2]})
end
-- We need to start the recursion with the second parameter containing
-- one blank element rather than no elements, otherwise no elements
-- will be propagated to the next recursion level.
return concat_word_forms_1(word_forms, {{""}})
end
local accel_forms = {
nom_sg = "nom|s",
nom_sg_linked = "nom|s",
nom_pl = "nom|p",
nom_pl_linked = "nom|p",
gen_sg = "gen|s",
gen_pl = "gen|p",
dat_sg = "dat|s",
dat_pl = "dat|p",
acc_sg_an = "an|acc|s",
acc_pl_an = "an|acc|p",
acc_sg_in = "in|acc|s",
acc_pl_in = "in|acc|p",
ins_sg = "ins|s",
ins_pl = "ins|p",
pre_sg = "pre|s",
pre_pl = "pre|p",
loc = "loc|s",
loc_pl = "loc|p",
voc = "voc|s",
voc_pl = "voc|p",
par = "par|s",
par_pl = "par|p",
count = "count form",
pauc = "pau",
}
-- Make the table
make_table = function(args)
local data = {}
data.after_title = " " .. args.heading
data.number = args.nonumber and "" or numbers[args.n]
local lemma_forms = args[args.n == "p" and "nom_pl" or "nom_sg"]
data.lemma = nom.show_form(args.explicit_lemma and {{args.explicit_lemma, args.explicit_lemmatr}} or
args[args.n == "p" and "nom_pl_linked" or "nom_sg_linked"], "lemma", nil, nil)
data.title = args.title or format(args.old and old_title_temp or title_temp, data)
local sg_an_in_equal = m_table.deepEquals(args.acc_sg_an, args.acc_sg_in)
local pl_an_in_equal = m_table.deepEquals(args.acc_pl_an, args.acc_pl_in)
for _, case in ipairs(displayable_cases) do
local accel_form = accel_forms[case]
if not accel_form then
error("Something wrong, can't find accelerator form for " .. case)
end
if (sg_an_in_equal and (case == "acc_sg_an" or case == "acc_sg_in") or
pl_an_in_equal and (case == "acc_pl_an" or case == "acc_pl_in")) then
accel_form = rsub(accel_form, "^[ai]n|", "")
end
if args.n == "p" then
accel_form = rsub(accel_form, "|p$", "")
end
data[case] = nom.show_form(args[case], false, accel_form, lemma_forms, "remove monosyllabic accents only lemma")
end
local temp = nil
if args.n == "s" then
data.nom_x = data.nom_sg
data.gen_x = data.gen_sg
data.dat_x = data.dat_sg
data.acc_x_an = data.acc_sg_an
data.acc_x_in = data.acc_sg_in
data.ins_x = data.ins_sg
data.pre_x = data.pre_sg
if sg_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
elseif args.n == "p" then
data.nom_x = data.nom_pl
data.gen_x = data.gen_pl
data.dat_x = data.dat_pl
data.acc_x_an = data.acc_pl_an
data.acc_x_in = data.acc_pl_in
data.ins_x = data.ins_pl
data.pre_x = data.pre_pl
data.par = data.par_pl
data.loc = data.loc_pl
data.voc = data.voc_pl
if pl_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
else
if pl_an_in_equal then
temp = "both_numbers"
elseif sg_an_in_equal then
temp = "both_numbers_split_animacy_plural_only"
else
temp = "both_numbers_split_animacy"
end
end
for _, extra_case in ipairs({
{"par", "partitive"},
{"loc", "locative"},
{"voc", "vocative"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "s" and args.n ~= "p" and args.any_overridden[case .. "_pl"] then
if not args.any_overridden[case] then
data[case] = ""
end
template = extra_case_template_with_plural
elseif args.n ~= "p" and args.any_overridden[case] or args.n == "p" and args.any_overridden[case .. "_pl"] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
for _, extra_case in ipairs({
{"count", "count form"},
{"pauc", "paucal"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "p" and args.any_overridden[case] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
local notes = get_arg_chain(args, "notes", "notes")
local all_notes = {}
for _, note in ipairs(args.internal_notes) do
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
for _, note in ipairs(notes) do
-- Here too.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
data.notes = table.concat(all_notes, "<br />")
data.notes_clause = data.notes ~= "" and format(notes_template, data) or ""
return format(templates[temp], data)
end
function extra_case_template(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
|
|-]===]):format(colspan)
end
function extra_case_template_with_plural(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
| {\op}{case}_pl{\cl}
|-]===]):format(colspan)
end
notes_template = [===[
<div style="width:100%;text-align:left;background:var(--wikt-palette-lightblue, #d9ebff);">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame" data-toggle-category="လဟုတ်စှ်ေ" style="max-width:MINWIDTHem">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);">{title}<span style="font-weight:normal;">{after_title}</span> </div>
<div class="NavContent">
{\op}| style="table-layout:fixed; text-align:center; max-width:MINWIDTHem; width:100%;" class="inflection inflection-table"
|- class="rowgroup"
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[|-{par_clause}{loc_clause}{voc_clause}{count_clause}{pauc_clause}
|{\cl}{notes_clause}</div></div></div>]===]
end
templates["both_numbers"] = template_prelude("45") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_sg_in}
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy_plural_only"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 rowspan=2 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["one_number"] = template_prelude("30") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
templates["one_number_split_animacy"] = template_prelude("35") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| {acc_x_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
return export
pzd202krc0md49rfmgo6ymxr4abcs1y
399798
399793
2026-07-21T02:55:32Z
Intobesa.bot
1035
Bot: ပွမကၠာဲစုတ်ယၟုနူဘာသာအၚ်္ဂလိက်
399798
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
nouns.
Author: Benwing, rewritten from early version by Wikitiki89
Form of arguments: One of the following:
1. LEMMA|DECL|PLSTEM (all arguments optional)
2. ACCENT|LEMMA|DECL|PLSTEM (all arguments optional)
3. multiple sets of arguments separated by the literal word "or"
Arguments:
ACCENT: Accent pattern (a b c d e f b' d' f' f''). Multiple values can
be specified, separated by commas. If omitted, defaults to a or b
depending on the position of stress on the lemma or
explicitly-specified declension.
LEMMA: Lemma form (i.e. nom sg or nom pl), with appropriately-placed
stress; or the stem, if an explicit declension is specified
(in this case, the declension usually looks like an ending, and
the stem is the portion of the lemma minus the ending). In the
first argument set (i.e. first set of arguments separated
by "or"), defaults to page name; in later sets, defaults to lemma
of previous set. A plural form can be given, and causes argument
n= to default to n=p (plural only). Normally, an accent is
required if multisyllabic, and unaccented monosyllables with
automatically be stressed; prefix with * to override both behaviors.
DECL: Declension field. Normally omitted to autodetect based on the
lemma form; see below.
PLSTEM: special plural stem (defaults to stem of lemma)
Additional named arguments:
a: animacy (a/an/anim = animate, i/in/inan = inanimate, b/bi/both/ai = both
(listing animate first in the headword), ia = both (listing inanimate
first in the headword), otherwise inanimate)
n: number restriction (p = plural only, s = singular only, b = both;
defaults to both unless the lemma is plural, in which case it
defaults to plural only)
CASE_NUM or acc_NUM_ANIM or par/loc/voc: override (or multiple
values separated by commas) for case/number combination;
forms auto-linked; can have raw links in it, can have an
ending "note" (*, +, 1, 2, 3, etc.)
pltail: Specify something (usually a * or similar) to attach to
the end of the last plural form when there's more than one. Used in
conjunction with notes= to indicate that alternative plural forms
are obsolete, poetic, etc.
pltailall: Similar pltail= but attaches to all plural forms.
Typically used in conjunction with notes= to make a comment about
the plural as a whole (e.g. it's mostly hypothetical, rare and
awkward, etc.).
sgtail, sgtailall: Same as pltail=, pltailall= but for the singular.
obltail, obltailall: Same as pltail=, pltailall= but for oblique cases
(not the nominative or accusative).
CASE_NUM_tail: Attach the argument to the end of the last form
(whether there's one or more than one) for the particular
case/number combination. Note that this doesn't work quite like
pltail= or sgtail= in that it doesn't skip adding the argument
when there's only one form.
CASE_NUM_tailall: Attach the argument to the end of all forms
specified for the particular case/number combination. Similar to
pltailall= or sgtailall=.
suffix: Add a suffix such as ся to all forms.
prefix: Add a prefix to all forms.
plhyp, plhypall, CASE_NUM_hyp, etc.: Same as pltail, pltailall,
CASE_NUM_tal, etc. but specify that the marked forms are
mostly hypothetical or rare/awkard. Generally you will want
plhypall=y to mark the plural as hypothetical.
Per word named arguments:
All of the above named arguments have per-word variants, e.g.
a1, a2, ...; n1, n2, ...; CASE_NUM1, CASE_NUM2, ...;
pltail1, pltail2, ...; etc. These apply to the individual words of a
form.
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
par: partitive
loc: locative
voc: vocative
Number abbreviations:
sg: singular
pl: plural
Animacy abbreviations:
an: animate
in: inanimate
Declension field:
One of the following for regular nouns:
(blank)
GENDER
-VARIANT
GENDER-VARIANT
$
DECLTYPE
DECLTYPE/DECLTYPE
(also, can append various special-case markers to any of the above)
Or one of the following for adjectival nouns:
+
+ь
$
+short, +mixed or +proper
+DECLTYPE
GENDER if present is m, f, n or 3f; for regular nouns, required if the
lemma ends in -ь or is plural, ignored otherwise. 3f is the same
as f but in the case of a plural lemma in -и, detects a
third-declension feminine with singular in -ь rather than a
first-declension feminine with singular in -а or -я.
VARIANT is one way of requesting variant declensions (see also special
case (1) for variant nom pls, and special case (2) for variant
gen pls). The currently allowed values are -ья (will select a
mixed declension that has some normal declension in its singular
and the -ья plural declension); -ин (for animate masculine nouns
in -ин with plural in -е -- note that this is autodetected in the
majority of cases where the ending in -янин or -анин); -ишко
(used for inanimate neuter-form diminutive masculine nouns in
-ишко [also сараю́шко] with nom pl -и and colloquial feminine-ending
alternants in some singular cases); -ище (similar to -ишко but
used for *animate* augmentative masculine neuter-form nouns in
-ище). Variants -ишко and -ище must be given with with special
case (1).
$ is indeclinable words. It is principally useful in multiword
expressions where some of the words are indeclinable.
DECLTYPE is an explicit declension type. Normally you shouldn't use
this, and should instead let the declension type be autodetected
based on the ending, supplying the appropriate hint if needed
(gender for regular nouns, +ь for adjectives). If provided, the
declension type is usually the same as the ending, and if present,
the lemma field should be just the stem, without the ending.
Possibilities for regular nouns are (blank) or # for hard-consonant
declension, а, я, о, е or ё, е́, й, ья, ье or ьё, ь-m, ь-f,
ин, ёнок or онок or енок, ёночек or оночек or еночек, мя,
-а or #-а, ь-я, й-я, о-и or о-ы, -ья or #-ья, $ (indeclinable).
Old-style (pre-reform) declensions use ъ instead of (blank), ъ-а
instead of -а, ъ-ья instead of -ья, and инъ, ёнокъ/онокъ/енокъ,
ёночекъ/оночекъ/еночекъ instead of the same without terminating ъ.
The declensions can also be written with an accent on them; this
chooses the same declension (except for е vs. е́), but causes
ACCENT to default to pattern b instead of a.
For adjectival nouns, you should normally supply just + and let
the ending determine the declension; supply +ь in the case of a
possessive adjectival noun in -ий, which have an extra -ь- in
most endings compared with normal adjectival nouns in -ий, but
which can't be distinguished based on the nominative singular.
You can also supply +short, +mixed or +proper, which constrains
the declension appropriately but still autodetects the
gender-specific and stress-specific variant. If you do supply
a specific declension type, as with regular nouns you need to
omit the ending from the lemma field and supply just the stem.
Possibilities are +ый, +ое, +ая, +ій, +ее, +яя, +ой, +о́е, +а́я,
+ьій, +ье, +ья, +-short or +#-short (masc), +о-short,
+о-stressed-short or +о́-short, +а-short, +а-stressed-short or
+а́-short, and similar for -mixed and -proper (except there aren't
any stressed mixed declensions).
DECLTYPE/DECLTYPE is used for nouns with one declension in the
singular and a different one in the plural, for cases that
PLVARIANT and special case (1) below don't cover.
Special-case markers:
(1) for Zaliznyak-style alternative nominative plural ending:
-а or -я for masculine, -и or -ы for neuter
(2) for Zaliznyak-style alternative genitive plural ending:
-ъ/none for masculine, -ей for feminine, -ов(ъ) for neuter,
-ей for plural variant -ья
* for reducibles (nom sg or gen pl has an extra vowel before the
final consonant as compared with the stem found in other cases)
;ё for Zaliznyak-style alternation between last е in stem and ё
TODO:
1. Multi-word issues:
-- FIXME: Make sure internal_notes handled correctly; we may run into issues
with multiple internal notes from different words, if we're not careful
to use different footnote symbols for each type of footnote (which we
don't do currently). [NOT DONE, MAY NOT DO]
-- Handling default lemma: With multiple words, we should probably split
the page name on spaces and default each word in turn [NOT DONE, MAY
NOT DO]
2a. FIXME: For -ишко diminutives and -ище augmentatives, should add an
appropriate category of some sort (currently marked by colloqfem= in
category).
2b. FIXME: Adding a note to dat_sg also adds it to loc_sg when it exists;
seems wrong. See луг.
2c. FIXME: When you have both d' and f in feminines and you use sgtail=*,
you get two *'s. See User:Benwing2/test-ru-noun-debug.
3. ADJECTIVE FIXMES:
3a. FIXME: Change calls to ru-adj11 to use the new proper name support in
ru-adjective.
3b. FIXME: Test that omitting a manual form in ru-adjective leaves the form as
a big dash.
3c. FIXME: какой-либо and какой-то display genitives with translit -go
instead of -vo. To fix this properly requires implementing real
manual translit for adjectives.
3d. FIXME: Implement real manual translit for adjectives.
5. [FIXME: Consider adding an indicator in the header line when the ё/e
alternation occurs. This is a bit tricky to calculate: If special case
;ё is given, but also if ё occurs in the stem and the accent pattern is
as follows -- for sg-only, b' d' f' f'', also b d f if the noun is masc
or 3rd-decl fem (i.e. nom-sg ending is non-syllabic); for pl-only,
e f f' f'', also b b' c if the gen pl is non-syllabic; for sg/pl,
any but a or b, also b if either nom sg or gen pl is non-syllabic. But
it gets more complicated due to overrides. An alternative is to check
all forms to see if ё is present in some but not all; but this is
tricky also because e.g. reducibles frequently have ё/null alternation,
which doesn't count, and some endings have е or ё in them, which also
doesn't count. If we were to do it this way, we'd have to (a) count
the number of е's in the form(s) with ё and verify that there's at least
one form without ё and with one more е than in the form(s) with ё
(and it gets trickier if different forms with ё have different numbers of
е in them, although that is probably rare); and (b) ignore the appropriate
endings (the best way to do this would probably be to look at the actual
suffixes that were generated in args.suffixes and chop off any matching
ending in the actual form(s), but also chop off final -е/ё, as well as
-ев(ъ)/-ёв(ъ)/-ей/-ёй in the gen pl, which is frequently overridden,
unless perhaps the stem ends in the same way). It'd probably not
possible to do this in a 100% foolproof way but can be "good enough" for
nearly all circumstances.] [MIGHT BE TOO MUCH WORK]
6. HEADWORD FIXMES:
6a. FIXME: In ru-headword, create a category for words whose gender doesn't
match the form. (This is easy to do for ru-noun+ but harder for ru-noun.
We would need to do limited autodetection of the ending: for singulars,
-а/я should be feminine, -е/о/ё should be neuter, -ь should be masculine
or feminine, anything else should be masculine; for plurals, -и/ы should
be masculine or feminine, -а/я should be neuter except that -ія can be
feminine or neuter due to old-style adjectival pluralia tantum nouns,
anything else can be any gender.)
6b. FIXME: Recognize indeclinable nouns and indicate as indeclinable. Probably
should work by checking the case forms to see if they're the same.
9. FIXME: Change stress-pattern detection and overriding to happen inside of
looping over the two parts of a slash decl. Requires that the loop over
the two parts happen outside of the loop over stress patterns. Requires
that the category code get split into two parts, one to handle combined
singular/plural categories that goes outside the two loops, and one to
handle everything else that goes inside the two loops.
10. FIXME: override_matches_suffix() had a free variable reference to ARGS
in it, which should have triggered an error whenever there was a nom_sg or
nom_pl override but didn't. Is there an error causing this never to be
called? Check.
11a. FIXME: In a multiword lemma, using loc2=+ causes only the second word
to get linked instead of the whole expression. Same for par2=+, voc2=+.
11b. FIXME: Using loc=+ with a multiword lemma should do the right thing, same
as if locN=+ is specified for each individual word. Instead it generates
the locative as a whole from the dative, which fails e.g. if some of the
words are adjectival. Same for par=+, voc=+.
13. Multi-word issues:
-- Setting n=pl when auto-detecting a plural lemma. How does that interact
with multi-word stuff? (DONE)
-- compute_heading() -- what to do with multiple words? I assume we should
display info on the first noun (non-indeclinable, non-adjectival), and
on the first adjectival word otherwise, and finally on an indeclinable word (DONE)
-- args.genders -- it should presumably come from the same word as is used
in compute_heading(); but we should allow the overall gender to be
overridden, at least in ru-noun+ (DONE)
-- Bug in args.suffix: Gets added to every word in attach_with() and then
again at the end, after pltail and such. Needs to be added to the
last word only, before pltail. Need also suffixN for individual words.
(DONE, NEEDS TESTING)
-- Should have ..N versions of pltail and variants. (DONE, NEEDS TESTING)
-- Need to handle overrides of acc_sg, acc_pl (DONE)
-- Overrides of nom_sg/nom_pl should also override acc_sg/acc_pl if it
was originally empty and the animacy is inanimate; similarly for
gen_sg/gen_pl and animates; this needs to work both for per-word and
overall overrides. (DONE)
-- do_generate_forms(_multi) need to run part of make_table(), enough to
combine all per_word_info into single lists of forms and store back
into args[case]. (DONE, NEEDS TESTING)
-- In generate_forms, should probably check if a=="i" and only return
acc_sg_in as acc_sg=; or if a=="a" and only return acc_sg_an as acc_sg=;
in old/new comparison code, do something similar, also when a=="b"
check if acc_sg_in==acc_sg_an and make it acc_sg; when a=="b" and the
_in and _an variants are different, might need to ignore them or check
that acc_sg_in==nom_sg and acc_sg_an==gen_sg; similarly for _pl
(DONE, NEEDS TESTING)
-- Need to test with multiple words! [DONE]
-- Current handling of <adj> won't work properly with multiple words;
will need to translate word-by-word in that case (should be solved by
manual-translit branch) [DONE]
14. In multiple-words branch, fix ru-decl-noun-multi so it recognizes
things like *, (1), (2) and ; without the need for a separator. Consider
using semicolon as a separator, since we already use it to separate ё
from a previous declension. Maybe use $ or ~ for an indeclinable word; don't
use semicolon. [IMPLEMENTED. NEED TO TEST.]
16. [Consider having ru-noun+ treat par= as a second genitive in
the headword, as is done with край] [WON'T DO]
17. [FIXME: Consider removing slash patterns and instead handling them by
allowing additional declension flags 'sg' and 'pl'. This simplifies the
various special cases caused by slash declensions. It would also be
possible to remove the special plural stem, which would get rid of more
special cases. On the other hand, it makes it more complicated to support
plural variant -ья with all singular types, and the category code that
displays things like "Russian nouns with singular -X and plural -Y"
also gets more complicated, and there's something convenient and intuitive
about plural stems, and slash declensions are also convenient and at least
somewhat intuitive. One possibility is to externally allow slash
declensions and special plural stems and rewrite them internally to
separate stems with 'sg' and 'pl' declension flags; but there are still
the two coding issues mentioned above.]
18. [FIXME: Consider redoing slash patterns so they operate at the outer
level, i.e. things like special cases apply separately in the singular
and plural part of the slash pattern.]
19. In ru-noun, don't recognize -а with m as plural unless (1)
or n=pl is also given, because there are masculine words with the
feminine ending. Check using the test code whether this changes
anything. Also check if there are other similar cases (neuter with
-и isn't parallel because -и is always plural). [IMPLEMENTED. NEED TO TEST.]
19a. Internal notes weren't propagated properly from adjectives.
[IMPLEMENTED. NEED TO TEST.]
19b. Add support for -ишко and -ище variants (p. 74 of Z),
which conversationally and/or colloquially have feminine endings in
certain cases. [IMPLEMENTED. NEED TO TEST. MAKE SURE THE INTERNAL NOTES
APPEAR.]
19d. For masculine animate neuter-form nouns, the accusative singular
ends in -а (-я soft) instead of -о. [IMPLEMENTED. NEED TO TEST.
NOTE: Currently this variant only can be selected using new-style
arguments where the gender can be given. Perhaps we should consider
allowing gender to be specified with old-style explicit declensions.]
21. Put back gender hints for pl adjectival nouns; used by ru-noun+.
[IMPLEMENTED. NEED TO TEST.]
23. Mixed and proper-noun adjectives have built-in notes. We need to
handle those notes with an "internal_notes" section similar to what is used
in the adjective module. [IMPLEMENTED. NEED TO TEST.]
24. Adjective detection code here needs to work the same as for the
adjective module, in particular in the handling of short, stressed-short,
mixed, proper, stressed-proper. [IMPLEMENTED. NEED TO TEST.]
25. Consider simplifying plural-variant code to only allow -ья as a
plural variant [and maybe even change that to be something like (1')].
[IMPLEMENTED REDUCTION OF PLURAL VARIANTS TO -ья; PLURAL-VARIANT CODE
STILL COMPLEX, THOUGH. NEED TO TEST.]
26. Automatically superscript *, numbers and similar things at the
beginning of a note. Also do this in adjective module. [IMPLEMENTED.
NEED TO TEST.]
28. Make the check for multiple stress patterns (categorizing/tracking)
smarter, to keep a list of them and check at the end, so we handle
multiple stress patterns specified through different arg sets.
[IMPLEMENTED; NEED TO TEST.]
29. More sophisticated handling of user-requested plural variant vs. special
case (1) vs. plural-detected variant. [IMPLEMENTED. NEED TO TEST FURTHER.]
30. Solution to ambiguous plural involving gender spec "3f". [IMPLEMENTED;
NEED TO TEST. Use запчасти, новости.]
33. With pluralia tantum adjectival nouns, we don't know the gender.
By default we assume masculine (or feminine for old-style -ія nouns) and
currently this goes into the category, but shouldn't. [IMPLEMENTED.]
39. [Eventually: Even with decl type explicitly given, the full stem with
ending should be included.] [MAY NEVER IMPLEMENT]
40. [Get error "Unable to dereduce" with strange noun ва́йя, what should
happen?] [WILL NOT FIX; USE AN OVERRIDE]
41. In творог, module generates partitive творогу́ when it should copy the
dative творогу́,тво́рогу. (DONE)
42. [[груз 200]] doesn't work. Interprets 200 as a footnote symbol.
43. When converting е -> ё not after cons and with translit, we should
convert e -> o to avoid double j. (DONE)
44. FIXME: In ро́вня/ровня́, similarly with неровня, marks genitive plural
ровня́ as irregular even though it isn't. (NOT OUR ERROR; THE DECLENSIONS
OF THESE NOUNS MARKED THE ENDING-STRESSED VARIANTS WITH (2).)
]=]--
local m_utilities = require("Module:utilities")
local m_table = require("Module:table")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local m_ru_adj = require("Module:ru-adjective")
local m_str_utils = require("Module:string utilities")
local scriptutils = require("Module:script utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
local Latn = require("Module:scripts").getByCode("Latn")
local format = m_str_utils.format
local rfind = m_str_utils.find
local rsubn = m_str_utils.gsub
local rmatch = m_str_utils.match
local rsplit = m_str_utils.split
local u = m_str_utils.char
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same. Eventually consider removing this;
-- but useful as new code is created.
local test_new_ru_noun_module = false
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local DIA = u(0x0308) -- diaeresis = ̈
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder, matching ru-common
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
local paucal_marker = "*"
local paucal_internal_note = "* Used with the numbers 1.5, 2, 3, 4 and higher numbers after 20 ending in 2, 3, and 4."
-- text class to check lowercase arg against to see if Latin text embedded in it
local latin_text_class = "[a-zščžěáéíóúýàèìòùỳâêîôûŷạẹịọụỵȧėȯẏ]"
-- Forward functions
local generate_forms_1
local determine_decl
local handle_forms_and_overrides
local handle_overall_forms_and_overrides
local concat_word_forms
local make_table
local detect_adj_type
local detect_stress_pattern
local override_stress_pattern
local determine_stress_variant
local determine_stem_variant
local is_reducible
local is_dereducible
local add_bare_suffix
local attach_stressed
local do_stress_pattern
local canonicalize_override
-- 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
-- version of rfind() that lowercases its string first, for case-insensitive matching
local function rlfind(term, foo)
return rfind(ulower(term), foo)
end
local function track(page)
m_debug.track("ru-noun/" .. page)
return true
end
-- version of m_table.insertIfNot() that makes sure 'false' doesn't get inserted by mistake.
local function insert_if_not(foo, bar)
assert(bar ~= false)
m_table.insertIfNot(foo, bar)
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-- FIXME: Move to utils
-- Iterate over a chain of parameters, FIRST then PREF2, PREF3, ...,
-- inserting into LIST (newly created if omitted). Return LIST.
local function get_arg_chain(args, first, pref, list)
if not list then
list = {}
end
local val = args[first]
local i = 2
while val do
table.insert(list, val)
val = args[pref .. i]
i = i + 1
end
return list
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
local function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
local function rutr_pairs_equal(term1, term2)
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
local ru1entry, ru1notes = m_table_tools.separate_notes(m_links.remove_links(ru1))
local ru2entry, ru2notes = m_table_tools.separate_notes(m_links.remove_links(ru2))
if ru1entry ~= ru2entry then
return false
end
local tr1entry, tr1notes
local tr2entry, tr2notes
if tr1 then
tr1entry, tr1notes = m_table_tools.separate_notes(tr1)
end
if tr2 then
tr2entry, tr2notes = m_table_tools.separate_notes(tr2)
end
if tr1entry == tr2entry then
return true
elseif type(tr1entry) == type(tr2entry) then
return false
else
tr1entry = tr1entry or com.translit_no_links(ru1entry)
tr2entry = tr2entry or com.translit_no_links(ru2entry)
return tr1entry == tr2entry
end
end
local function contains_rutr_pair(list, pair)
for _, item in ipairs(list) do
if rutr_pairs_equal(item, pair) then
return true
end
end
return false
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
args[pname] = ine(param)
end
return args
end
-- Old-style declensions.
local declensions_old = {}
-- New-style declensions; computed automatically from the old-style ones,
-- for the most part.
local declensions = {}
-- Internal notes for old-style declensions.
local internal_notes_table_old = {}
-- Same for new-style declensions.
local internal_notes_table = {}
-- Category and type information corresponding to declensions: These may
-- contain the following fields: 'singular', 'plural', 'decl', 'hard', 'g',
-- 'suffix', 'gensg', 'irregpl', 'alt_nom_pl', 'cant_reduce', 'ignore_reduce',
-- 'stem_suffix'.
--
-- 'singular' is used to construct a category of the form
-- "Russian nouns SINGULAR". If omitted, a category is constructed of the
-- form "Russian nouns ending in -ENDING", where ENDING is the actual
-- nom sg ending shorn of its acute accents; or "Russian nouns ending
-- in suffix -ENDING", if 'suffix' is true. The value of SINGULAR can be
-- one of the following: a single string, a list of strings, or a function,
-- which is passed one argument (the value of ENDING that would be used to
-- auto-initialize the category), and should return a single string or list
-- of strings. Such a category is only constructed if 'gensg' is true.
--
-- 'plural' is analogous but used to construct a category of the form
-- "Russian nouns with PLURAL", and if omitted, a category is constructed
-- of the form "Russian nouns with plural -ENDING", based on the actual
-- nom pl ending shorn of its acute accents. Currently no plural category
-- is actually constructed.
--
-- In addition, a category may normally constructed from the combination of
-- 'singular' and 'plural', appropriately defaulted; e.g. if both are present,
-- the combined category will be "Russian nouns SINGULAR with PLURAL" and
-- if both are missing, the combined category will be
-- "Russian nouns ending in -SGENDING with plural -PLENDING" (or
-- "Russian nouns ending in suffix -SGENDING with plural -PLENDING" if
-- 'suffix' is true). Note that if either singular or plural or both
-- specifies a list, looping will occur over all combinations. Such a
-- category is constructed only if 'irregpl' or 'alt_nom_pl' or 'suffix'
-- is true or if the declension class is a slash class.
--
-- 'decl' is "1st", "2nd", "3rd" or "indeclinable"; 'hard' is "hard", "soft"
-- or "none"; 'g' is "m", "f", "n" or "none"; these are all traditional
-- declension categories.
--
-- If 'suffix' is true, the declension type includes a long suffix
-- added to the string that itself undergoes reducibility and such, and so
-- reducibility cannot occur in the stem minus the suffix. Categories will
-- be created for the suffix.
--
-- 'alt_nom_pl' indicates that the declension has an alternative nominative
-- plural (corresponding to Zaliznyak's special case 1; compare special case 2
-- for alternative genitive plural). 'irregpl' indicates that the entire
-- plural is irregular.
--
-- In addition to the above categories, additional more specific categories
-- are constructed based on the final letter of the stem, e.g.
-- "Russian velar-stem 1st-declension hard nouns". See calls to
-- com.get_stem_trailing_letter_type(). 'stem_suffix', if present, is added to
-- the end of the stem when get_stem_trailing_letter_type() is called.
-- This is the only place that 'stem_suffix' is used. This is for use with
-- the '-ья' and '-ье' declension types, so that the trailing letter is
-- 'ь' and not whatever precedes it.
--
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
-- Category/type info corresponding to old-style declensions; see above.
local declensions_old_cat = {}
-- Category/type info corresponding to new-style declensions. Computed
-- automatically from the old-style ones, for the most part. Same format
-- as the old-style ones.
local declensions_cat = {}
-- Table listing aliases of old-style declension classes.
local declensions_old_aliases = {}
-- Table listing aliases of new-style declension classes; computed
-- automatically from the old-style ones.
local declensions_aliases = {}
local stress_patterns = {}
-- Set of patterns with ending-stressed genitive plural.
local ending_stressed_gen_pl_patterns = {}
-- Set of patterns with ending-stressed prepositional singular.
local ending_stressed_pre_sg_patterns = {}
-- Set of patterns with ending-stressed dative singular.
local ending_stressed_dat_sg_patterns = {}
-- Set of patterns with all singular forms ending-stressed.
local ending_stressed_sg_patterns = {}
-- Set of patterns with all plural forms ending-stressed.
local ending_stressed_pl_patterns = {}
local declinable_cases_except_accusative = {
"nom_sg", "gen_sg", "dat_sg", "ins_sg", "pre_sg",
"nom_pl", "gen_pl", "dat_pl", "ins_pl", "pre_pl",
}
local accusative_cases_unsplit_animacy = {
"acc_sg", "acc_pl",
}
local accusative_cases_split_animacy = {
"acc_sg_an", "acc_sg_in", "acc_pl_an", "acc_pl_in",
}
local lemma_linked_cases = {
"nom_sg_linked", "nom_pl_linked",
}
local overridable_only_cases = {
"par", "loc", "voc", "par_pl", "loc_pl", "voc_pl", "count", "pauc",
}
local overridable_only_cases_set = m_table.listToSet(overridable_only_cases)
-- List of all cases that are declined normally.
local decl_cases = m_table.append(declinable_cases_except_accusative, accusative_cases_unsplit_animacy)
-- List of all cases that can be overridden (includes all cases except the "linked" lemma case variants). Also
-- currently the same as the cases returned by export.generate_forms().
local overridable_cases = m_table.append(decl_cases, accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases that can be displayed (includes all cases except plain accusatives).
local displayable_cases = m_table.append(declinable_cases_except_accusative, lemma_linked_cases,
accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases, including those that are declined normally (nom/gen/dat/acc/ins/pre sg and pl), plus
-- animate/inanimate accusative variants (computed automatically as appropriate from the previous cases), plus
-- additional overridable cases (loc/par/voc and plural), plus the "linked" lemma case variants used in ru-noun+
-- headwords (nom_sg_linked, nom_pl_linked, whose values come from nom_sg and nom_pl but may have additional embedded
-- links if they were given in the lemma).
local all_cases = m_table.append(overridable_cases, lemma_linked_cases)
local function english_case_description(case)
if case == "par" or case == "loc" or case == "voc" then
-- For historical reasons, the singular of these cases doens't include "_sg" in their code.
case = case .. "_sg"
end
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
par="partitive", loc="locative", voc="vocative",
count="count form", pauc="paucal form",
})
engcase = rsub(engcase, "(_[a-z]*)", {
_sg=" singular", _pl=" plural",
_an="", _in="",
--_an=" animate", _in=" inanimate"
})
return engcase
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
-- FIXME! Move below the main code
-- FIXME!! Consider deleting most of this tracking code once we've enabled
-- all the categories. Note that some of the tracking categories aren't
-- completely redundant; e.g. we have tracking pages that combine decl and
-- stress classes, such as "а/a" or "о-и/d'", which are more or less
-- equivalent to stem/gender/stress categories, but we also have the same
-- prefixed by "reducible-stem/" for reducible stems.
local function tracking_code(stress, orig_decl, decl, args, n, islast)
assert(orig_decl)
assert(decl)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
if orig_decl == decl then
orig_decl = nil
end
if args.notes then
track("notes")
end
local function all_pl_irreg()
track("irreg")
for _, case in ipairs(overridable_cases) do
if rfind(case, "_pl") then
track("irreg/" .. case)
end
end
end
local function track_prefix(prefix)
local function dotrack(suf)
track(prefix .. suf)
end
dotrack(stress)
dotrack(decl)
dotrack(decl .. "/" .. stress)
if orig_decl then
dotrack(orig_decl)
dotrack(orig_decl .. "/" .. stress)
end
for _, hint_type in ipairs(hint_types) do
dotrack(hint_type)
dotrack(decl .. "/" .. hint_type)
if orig_decl then
dotrack(orig_decl .. "/" .. hint_type)
end
end
end
track_prefix("")
if args.reducible then
track("reducible-stem")
track_prefix("reducible-stem/")
end
if rlfind(args.stem, "и́?н$") and (decl == "" or decl == "#") then
track("irregular-in")
end
if args.pltail then
track("pltail")
end
if args.sgtail then
track("sgtail")
end
if args.pltailall then
track("pltailall")
end
if args.sgtailall then
track("sgtailall")
end
if args.pl ~= args.stem then
track("irreg-pl-stem")
track("irreg")
end
if args.alt_gen_pl then
track("alt-gen-pl")
track("irreg")
track("irreg/gen_pl")
end
if args.want_sc1 then
track("want-sc1")
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-и$") or rfind(decl, "-а$") or rfind(decl, "-я$") then
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-ья$") then
track("variant-ья")
all_pl_irreg()
end
if rfind(decl, "%(ишк%)$") then
track("variant-ишко")
end
if rfind(decl, "%(ищ%)$") then
track("variant-ище")
end
if args.jo_special then
track("jo-special")
end
if args.manual then
track("manual")
end
if args.explicit_gender then
track("explicit-gender")
track("explicit-gender/" .. args.explicit_gender)
end
for _, case in ipairs(overridable_cases) do
if args[case .. n] and not args.manual then
track("override")
track("override/" .. case .. n)
track("irreg")
track("irreg/" .. case .. n)
-- questionable use: track_prefix("irreg/" .. case .. "/")
-- questionable use: track_prefix("irreg/" .. case .. n .. "/")
end
if islast and args[case] and not args.manual then
track("override")
track("override/" .. case)
track("irreg")
track("irreg/" .. case)
-- questionable use: track_prefix("irreg/" .. case .. "/")
end
if args[case .. "_tail"] then
track("casenum-tail")
track("casenum-tail/" .. case)
end
if args[case .. "_tailall"] then
track("casenum-tailall")
track("casenum-tailall/" .. case)
end
end
end
local gender_to_full = {m="ပုလ္လိၚ်", f="ဣတ္တိလိၚ်", n="နပုလ္လိၚ်"}
local gender_to_short = {m="masc", f="fem", n="neut"}
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the plural part of speech.
local function insert_category(categories, cat, pos, atbeg)
if enable_categories then
-- local fullcat = "Russian " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(categories, 1, fullcat)
else
table.insert(categories, fullcat)
end
end
end
-- Insert categories into ARGS.CATEGORIES corresponding to the specified
-- stress and declension classes and to the form of the stem (e.g. velar,
-- sibilant, etc.). Also initialize values used to compute the declension
-- heading that describes similar information. N is the number of the
-- word being processed; ISLAST is true if this is the last word.
local function categorize_and_init_heading(stress, decl, args, n, islast)
local function cat_to_list(cat)
if not cat then
return {}
elseif type(cat) == "string" then
return {cat}
else
assert(type(cat) == "table")
return cat
end
end
-- Insert category CAT into the list of categories in ARGS.
-- CAT may be nil, a single string or a list of strings. We call
-- insert_category() on each string. The strings will have "Russian "
-- prepended and "~" replaced with the plural part of speech.
local function insert_cat(cat)
for _, c in ipairs(cat_to_list(cat)) do
insert_category(args.categories, c, args.pos)
end
end
-- "Resolve" the category spec CATSPEC into the sort of category spec
-- accepted by insert_cat(), i.e. nil, a single string or a list of
-- strings. CATSPEC may be any of these or a function, which takes one
-- argument (SUFFIX) and returns another CATSPEC.
local function resolve_cat(catspec, suffix)
if type(catspec) == "function" then
return resolve_cat(catspec(suffix), suffix)
else
return catspec
end
end
-- Check whether an override for nom_sg or nom_pl still contains the
-- normal suffix (which should already have accents removed) in at least
-- one of its entries. If no override then of course we return true.
local function override_matches_suffix(args, case, n, suffix)
assert(suffix == com.remove_accents(suffix))
-- NOTE: It might not be completely correct to pass in args.forms
-- here when n == ""; this is different behavior from
-- handle_overall_forms_and_overrides(). But args.forms is only used
-- to retrieve the dat_sg for handling loc/par, and we're never
-- called with loc or par as the value of CASE, so it doesn't matter.
-- We add an assert to make sure of this.
assert(case ~= "loc" and case ~= "par")
local override = canonicalize_override(args, case, args.forms, n)
if not override then
return true
end
for _, x in ipairs(override) do
local ru, tr = x[1], x[2]
local entry, notes = m_table_tools.separate_notes(ru)
entry = com.remove_accents(m_links.remove_links(entry))
if rlfind(entry, suffix .. "$") then
return true
end
end
return false
end
if args.manual then
return
end
local h = args.heading_info
assert(decl)
local decl_cats = args.old and declensions_old_cat or declensions_cat
local sgdecl, pldecl
local is_slash_decl = rfind(decl, "/")
if is_slash_decl then
local indiv_decls = rsplit(decl, "/")
sgdecl, pldecl = indiv_decls[1], indiv_decls[2]
else
sgdecl, pldecl = decl, decl
end
local sgdc = decl_cats[sgdecl]
local pldc = decl_cats[pldecl]
assert(sgdc)
assert(pldc)
local sghint_types = com.get_stem_trailing_letter_type(
args.stem .. (sgdc.stem_suffix or ""))
-- insert English version of Zaliznyak stem type
if sgdc.decl == "indeclinable" then
insert_cat("indeclinable ~")
insert_if_not(h.stemetc, "indecl")
else
local stem_type =
sgdc.decl == "3rd" and "3rd-declension" or
m_table.contains(sghint_types, "velar") and "velar-stem" or
m_table.contains(sghint_types, "sibilant") and "sibilant-stem" or
m_table.contains(sghint_types, "c") and "ц-stem" or
m_table.contains(sghint_types, "i") and "i-stem" or
m_table.contains(sghint_types, "vowel") and "vowel-stem" or
m_table.contains(sghint_types, "soft-cons") and "vowel-stem" or
m_table.contains(sghint_types, "palatal") and "vowel-stem" or
sgdc.hard == "soft" and "soft-stem" or
"hard-stem"
local short_stem_type = stem_type == "3rd-declension" and "3rd-decl" or stem_type
if sgdc.adj then
-- Don't include gender for pluralia tantum because it's mostly
-- indeterminate (certainly when specified using a plural lemma,
-- which will be usually; technically it's partly or completely
-- determinate in certain old-style adjectives that distinguish
-- masculine from feminine/neuter, but this is too rare a case
-- to worry about)
local gendertext = args.thisn == "p" and "plural-only" or gender_to_full[sgdc.g]
insert_if_not(h.adjectival, "yes")
if args.thisn ~= "p" then
insert_if_not(h.gender, gender_to_short[sgdc.g])
end
if sgdc.possadj then
insert_cat(sgdc.decl .. " possessive " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, sgdc.decl .. " poss")
insert_if_not(h.stress, stress)
elseif stem_type == "soft-stem" or stem_type == "vowel-stem" then
insert_cat(stem_type .. " " .. gendertext .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
else
insert_cat(stem_type .. " " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
else
-- NOTE: There are 8 Zaliznyak-style stem types and 3 genders, but
-- we don't create a category for masculine-form 3rd-declension
-- nouns (there is such a noun, путь, but it mostly behaves
-- like a feminine noun), so there are 23.
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form ~")
-- NOTE: Here we are creating categories for the combination of
-- stem, gender and accent. There are 10 accent patterns and 23
-- combinations of stem and gender, which potentially makes for
-- 10*23 = 230 such categories, which is a lot. Not all such
-- categories should actually exist; there were maybe 75 former
-- declension templates, each of which was essentially categorized
-- by the same three variables, but some of which dealt with
-- ancillary issues like irregular plurals; this amounts to 67
-- actual stem/gender/accent categories, although there are more
-- of them in Zaliznyak (FIXME, how many? See generate_cats.py).
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " ~")
insert_if_not(h.adjectival, "no")
insert_if_not(h.gender, gender_to_short[sgdc.g])
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
insert_cat("~ with accent pattern " .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
local sgsuffix = args.suffixes.nom_sg
if sgsuffix then
assert(#sgsuffix == 1) -- If this ever fails, then implement a loop
sgsuffix = com.remove_accents(sgsuffix[1])
-- If we are plural only or if nom_sg is overridden and has
-- an unusual suffix, then don't create category for sg suffix
if args.thisn == "p" or not override_matches_suffix(args, "nom_sg", n, sgsuffix) or islast and not override_matches_suffix(args, "nom_sg", "", sgsuffix) then
sgsuffix = nil
end
end
local plsuffix = args.suffixes.nom_pl
if plsuffix then
assert(#plsuffix == 1) -- If this ever fails, then implement a loop
plsuffix = com.remove_accents(plsuffix[1])
-- If we are a singulare tantum or if nom_pl is overridden and has
-- an unusual suffix, then don't create category for pl suffix
if args.thisn == "s" or not override_matches_suffix(args, "nom_pl", n, plsuffix) or islast and not override_matches_suffix(args, "nom_pl", "", plsuffix) then
plsuffix = nil
end
end
sgsuffix = sgsuffix and rsub(sgsuffix, "ъ$", "")
plsuffix = plsuffix and rsub(plsuffix, "ъ$", "")
local sgcat = sgsuffix and (resolve_cat(sgdc.singular, sgsuffix) or "ending in " .. (sgsuffix == "" and "a consonant" or (sgdc.suffix and "suffix " or "") .. "-" .. sgsuffix))
local plcat = plsuffix and (resolve_cat(pldc.plural, plsuffix) or "plural -" .. plsuffix)
if sgcat and sgdc.gensg then
for _, cat in ipairs(cat_to_list(sgcat)) do
insert_cat("~ " .. cat)
end
end
if sgcat and plcat and (sgdc.suffix or sgdc.alt_nom_pl or sgdc.irregpl or
is_slash_decl and plsuffix == "-ья") then
for _, scat in ipairs(cat_to_list(sgcat)) do
for _, pcat in ipairs(cat_to_list(plcat)) do
-- insert_cat("~ " .. scat .. " with " .. pcat)
end
end
end
if args.pl ~= args.stem then
-- insert_cat("~ with irregular plural stem")
end
if args.reducible and not sgdc.ignore_reduce then
-- insert_cat("~ with reducible stem")
if args.soft_n then
-- insert_cat("~ with soft final н in reduced stem")
end
insert_if_not(h.reducible, "yes")
else
insert_if_not(h.reducible, "no")
end
if args.alt_gen_pl then
-- insert_cat("~ with alternative genitive plural")
end
if sgdc.adj then
-- insert_cat("adjectival ~")
end
end
local function compute_heading(args)
local headings = {}
local h = args.heading_info
table.insert(headings, args.a == "a" and "anim" or args.a == "i" and
"inan" or "bian")
table.insert(headings, args.nonumber and "uncountable" or
args.n == "s" and "sg-only" or args.n == "p" and "pl-only" or nil)
if #h.gender > 0 then
table.insert(headings, table.concat(h.gender, "/") .. "-form")
end
if #h.stemetc > 0 then
table.insert(headings, table.concat(h.stemetc, "/"))
end
if #h.stress > 0 then
local stresses = {}
for _, stress in ipairs(h.stress) do
table.insert(stresses, (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
table.insert(headings, "accent-" .. table.concat(stresses, "/"))
end
local function handle_bool(boolvals, text, into)
into = into or headings
if m_table.contains(boolvals, "yes") and m_table.contains(boolvals, "no") then
table.insert(into, "[" .. text .. "]")
elseif m_table.contains(boolvals, "yes") then
table.insert(into, text)
end
end
handle_bool(h.adjectival, "adj")
handle_bool(h.reducible, "reduc")
return headings
end
local function compute_overall_heading_categories_and_genders(args)
local hinfo = args.per_word_heading_info
local index = 0
-- First try for non-adjectival, non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") and not m_table.contains(hinfo[i].adjectival, "yes") then
index = i
break
end
end
if index == 0 then
-- Then just non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") then
index = i
break
end
end
end
-- Finally, do anything
if index == 0 then
index = 1
end
-- Compute final heading
local headings = args.per_word_headings[index]
local categories = args.per_word_categories[index]
if args.any_irreg then
table.insert(headings, "irreg")
-- insert_category(categories, "irregular ~", args.pos)
end
for _, case in ipairs(overridable_cases) do
local is_pl = rfind(case, "_pl")
if args.n == "s" and is_pl or args.n == "p" and not is_pl then
-- Don't create singular categories when plural-only or vice-versa
elseif overridable_only_cases_set[case] then
if args.any_overridden[case] then
-- insert_category(categories, "~ with " .. english_case_description(case), args.pos)
end
elseif args.any_irreg_case[case] then
-- insert_category(categories, "~ with irregular " .. english_case_description(case), args.pos)
end
end
local heading = args.manual and "" or "(<span style=\"font-size: smaller;\">[[Appendix:Russian nouns#Declension tables|" .. table.concat(headings, " ") .. "]]</span>)"
args.heading = heading
args.categories = categories
args.genders = args.per_word_genders[index]
end
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Used by do_generate_forms().
local function arg1_is_stress(arg1)
if not arg1 then return false end
for _, arg in ipairs(rsplit(arg1, ",")) do
if not rfind(arg, "^[a-f]'?'?$") then
return false
end
end
return true
end
-- Used by do_generate_forms(), handling a word joiner argument
-- of the form 'join:JOINER'.
local function extract_word_joiner(spec)
word_joiner = rmatch(spec, "^join:(.*)$")
assert(word_joiner)
return com.split_russian_tr(word_joiner, "dopair")
end
local function determine_headword_gender(args, sgdc, gender)
-- If gender unspecified, use normal gender of declension, except when
-- adjectival nouns that are pluralia tantum, where the gender is
-- mostly indeterminate (FIXME, not completely with old-style declensions
-- but we don't handle that currently).
if not gender then
if sgdc.adj and args.thisn == "p" then
gender = nil
else
gender = sgdc.g
end
end
-- Determine headword genders
gender = gender and gender ~= "none" and gender .. "-" or ""
local plsuffix = args.n == "p" and "-p" or ""
local hgens
if args.a == "a" then
hgens = {gender .. "an" .. plsuffix}
elseif args.a == "i" then
hgens = {gender .. "in" .. plsuffix}
elseif args.a == "ai" then
hgens = {gender .. "an" .. plsuffix, gender .. "in" .. plsuffix}
else
hgens = {gender .. "in" .. plsuffix, gender .. "an" .. plsuffix}
end
-- Insert into list of genders
for _, hgen in ipairs(hgens) do
insert_if_not(args.genders, hgen)
end
end
function export.do_generate_forms(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SETS and JOINER, where ARG_SETS
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Gather arguments into a list of ARG_SET objects, containing (potentially)
-- elements 1, 2, 3, 4, corresponding to accent pattern, stem, declension
-- type, pl stem and coming from consecutive numbered parameters. Sets of
-- declension parameters are separated by the word "or".
local arg_sets = {}
-- Find maximum-numbered arg, allowing for holes
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Now gather the arguments.
local offset = 0
local arg_set = {}
for i=1,(max_arg + 1) do
local end_arg_set = false
local end_word = false -- FIXME, is this correct?
local word_joiner
if i == max_arg + 1 then
end_arg_set = true
end_word = true
word_joiner = {""}
elseif args[i] == "_" then
end_arg_set = true
end_word = true
word_joiner = {" "}
elseif args[i] == "-" then
end_arg_set = true
end_word = true
word_joiner = {"-"}
elseif args[i] and rfind(args[i], "^join:") then
end_arg_set = true
end_word = true
word_joiner = extract_word_joiner(args[i])
elseif args[i] == "or" then
end_arg_set = true
end
if end_arg_set then
table.insert(arg_sets, arg_set)
arg_set = {}
offset = i
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
else
-- If the first argument isn't stress, that means all arguments
-- have been shifted to the left one. We want to shift them
-- back to the right one, so we change the offset so that we
-- get the same effect of skipping a slot in the arg set.
if i - offset == 1 and not arg1_is_stress(args[i]) then
offset = offset - 1
end
if i - offset > 4 then
error("Too many arguments for argument set: arg " .. i .. " = " .. (args[i] or "(blank)"))
end
arg_set[i - offset] = args[i]
end
end
return generate_forms_1(args, per_word_info)
end
function export.do_generate_forms_multi(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SET and JOINER, where ARG_SET
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Find maximum-numbered arg, allowing for holes (FIXME: Is this needed
-- here? Will there be holes?)
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Gather arguments into a list of ARG_SET objects, containing
-- (potentially) elements 1, 2, 3, corresponding to accent pattern,
-- lemma+declension spec, pl stem, exactly as with do_generate_forms()
-- and {{ru-noun-table}} except that the values come from a single argument
-- of the form ACCENTPATTERN:LEMMADECL:PL where all but LEMMADECL may (and
-- probably will be) omitted and LEMMADECL may be of the following forms:
-- LEMMA (for a noun with empty decl spec),
-- LEMMADECL (for a noun with non-empty decl spec beginning with a
-- *, left paren or semicolon),
-- LEMMA^DECL (for a noun with non-empty decl spec),
-- LEMMA$ (for an indeclinable word)
-- LEMMA+ (for an adjective with auto-detected decl class)
-- LEMMA+DECL (for an adjective with explicit decl class)
-- Sets of parameters for the same word are separated by the word "or".
local arg_sets = {}
local continue_arg_sets = true
for i=1,(max_arg + 1) do
local end_word = false
local word_joiner
local process_arg = false
if i == max_arg + 1 then
end_word = true
word_joiner = {""}
elseif args[i] == "-" then
end_word = true
word_joiner = {"-"}
continue_arg_sets = true
elseif rfind(args[i], "^join:") then
end_word = true
word_joiner = extract_word_joiner(args[i])
continue_arg_sets = true
elseif args[i] == "or" then
continue_arg_sets = true
else
if continue_arg_sets then
continue_arg_sets = false
else
end_word = true
word_joiner = {" "}
end
process_arg = true
end
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
if process_arg then
local vals = rsplit(args[i], ":")
if #vals > 3 then
error("Can't specify more than 3 colon-separated params of param set: " .. args[i])
end
local arg_set = {}
if arg1_is_stress(vals[1]) then
arg_set[1] = vals[1]
arg_set[2] = vals[2]
arg_set[4] = vals[3]
else
arg_set[2] = vals[1]
arg_set[4] = vals[2]
end
-- recognize indeclinable
local indecl_stem = rmatch(arg_set[2], "^(.-)%$$")
if indecl_stem then
arg_set[2] = indecl_stem
arg_set[3] = "$"
else
-- recognize adjective
local adj_stem, adj_type = rmatch(arg_set[2], "^(.*)(%+.*)$")
if adj_stem then
arg_set[2] = adj_stem
arg_set[3] = adj_type
else
-- recognize noun with ^
local noun_stem, noun_type = rmatch(arg_set[2], "^(.*)%^(.*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- recognize noun without ^ but with decl spec
noun_stem, noun_type = rmatch(arg_set[2], "^(..-)([;*(].*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- noun without ^ or decl spec; nothing to do
end
end
end
end
table.insert(arg_sets, arg_set)
end
end
return generate_forms_1(args, per_word_info)
end
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence.
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence,
-- as well as show_z() for template {{ru-decl-noun-z}}, which has a
-- subset of the functionality of the other two.
generate_forms_1 = function(args, per_word_info)
local orig_args
if test_new_ru_noun_module then
orig_args = mw.clone(args)
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local old = args.old
local function verify_animacy_value(val)
if not val then return nil end
if val == "a" or val == "an" or val == "anim" then
return "a"
elseif val == "i" or val == "in" or val == "inan" then
return "i"
elseif val == "b" or val == "bi" or val == "both" or val == "ai" then
return "ai"
elseif val == "ia" then
return "ia"
end
error("Animacy value " .. val .. " should be empty or a/an/anim (animate), i/in/inan (inanimate), b/bi/both/ai (bianimate, listing animate first), or ia (bianimate, listing inanimate first)")
return nil
end
local function verify_number_value(val, allow_none)
if not val then return nil end
local short = usub(val, 1, 1)
if short == "s" or short == "p" or short == "b" or (allow_none and short == "n" or false) then
return short
end
if allow_none then
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), 'b' (both) or 'n' (none)")
else
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), or 'b' (both)")
end
return nil
end
-- Verify and canonicalize animacy, number, prefix, suffix
assert(#per_word_info >= 1)
for i=1,#per_word_info do
args["a" .. i] = verify_animacy_value(args["a" .. i])
args["n" .. i] = verify_number_value(args["n" .. i])
args["prefix" .. i] = com.split_russian_tr(args["prefix" .. i] or "", "dopair")
args["suffix" .. i] = com.split_russian_tr(args["suffix" .. i] or "", "dopair")
end
args.a = verify_animacy_value(args.a) or "i"
-- args.ndef, if set, is the default value for args.n; if unset, it defaults
-- to "both". It is set to "singular" in ru-proper noun+. We store the value
-- of args.n in args.orign before defaulting to args.ndef because we may
-- change it to plural-only later on if it was unspecified (this happens if
-- an individual word's lemma is plural), and to determine whether it was
-- unspecified, we need the original value before defaulting.
args.n = verify_number_value(args.n, "allow none")
-- treat n=none like n=sg but set a flag so "singular" isn't displayed
if args.n == "n" then
args.n = "s"
args.nonumber = true
end
args.ndef = verify_number_value(args.ndef)
args.orign = args.n
args.n = args.n or args.ndef
args.prefix = com.split_russian_tr(args.prefix or "", "dopair")
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
-- Attach overall prefix to first per-word prefix, similarly for suffix
args.prefix1 = com.concat_paired_russian_tr(args.prefix, args.prefix1)
args["suffix" .. #per_word_info] = com.concat_paired_russian_tr(
args["suffix" .. #per_word_info], args.suffix)
-- Initialize non-word-specific arguments.
--
-- The following is a list of WORD_INFO items, one per word, each of
-- which is a two element list of WORD_FORMS (a table listing the forms for
-- each case) and JOINER (a string, indicating how to join the word with
-- the next one).
args.per_word_info = {}
-- List of HEADING_INFO items, one per word, containing the raw material
-- used to generate the header. Initialized from 'args.heading_info',
-- which is initialized in categorize_and_init_heading().
args.per_word_heading_info = {}
-- List of CATEGORIES items, one per word, containing the categories
-- used to initialize the page categories. Initialized from
-- 'args.categories', which is initialized in categorize_and_init_heading().
args.per_word_categories = {}
-- List of HEADINGS items, one per word, containing the actual words that
-- go into the header if we were to use that word to construct the header.
-- Comes from compute_heading(). We use this to generate the actual header
-- string, which goes into 'args.heading' at the end (done in
-- compute_overall_heading_categories_and_genders()).
args.per_word_headings = {}
-- List of GENDERS items, one per word, containing the headword genders
-- for each word (where "headword gender" is in the format used in
-- headwords and actually includes animacy and number as well, e.g.
-- 'm-in' or 'f-an-p'). We end up selecting one such item and putting
-- it into 'args.genders' at the end
-- (in compute_overall_heading_categories_and_genders()).
args.per_word_genders = {}
args.any_overridden = {}
args.any_non_nil = {}
args.any_irreg = false
args.any_irreg_case = {}
local function insert_cat(cat)
insert_category(args.categories, cat, args.pos)
end
args.internal_notes = {}
local decl_sufs = old and declensions_old or declensions
local decl_cats = old and declensions_old_cat or declensions_cat
local intable = old and internal_notes_table_old or internal_notes_table
-- Default lemma defaults to previous lemma, first one to page name.
-- FIXME: With multiple words, we should probably split the page name
-- on spaces and default each word in turn
local default_lemma
local all_stresses_seen
-- Made into a function to avoid having to indent a lot of code.
-- Process a single arg set of a single word. This inserts the forms
-- for the word into args.forms and sets categories and tracking pages.
local function do_arg_set(arg_set, n, islast)
local stress_arg = arg_set[1]
local decl = arg_set[3] or ""
local pl, pltr
if arg_set[4] then
pl, pltr = com.split_russian_tr(arg_set[4])
end
-- Extract special markers from declension class.
if decl == "manual" then
decl = "$"
args.manual = true
if #per_word_info > 1 or #per_word_info[1][1] > 1 then
error("Can't specify multiple words or argument sets when manual")
end
if pl then
error("Can't specify optional stem parameters when manual")
end
end
decl, args.jo_special = rsubb(decl, "([^/%a])ё$", "%1")
if not args.jo_special then
decl, args.jo_special = rsubb(decl, "([^/%a])ё([^/%a])", "%1%2")
end
decl, args.want_sc1 = rsubb(decl, "%(1%)", "")
decl, args.alt_gen_pl = rsubb(decl, "%(2%)", "")
decl, args.reducible = rsubb(decl, "%*", "")
decl, args.soft_n = rsubb(decl, "%(нь%)", "")
decl = rsub(decl, ";", "")
-- Get the lemma.
local lemma = args.manual and "-" or arg_set[2] or default_lemma
if not lemma then
error("Lemma in first argument set must be specified")
end
default_lemma = lemma
local lemmatr
lemma, lemmatr = com.split_russian_tr(lemma)
-- If we're conjugating a suffix, insert a pseudoconsonant at the beginning
-- of all forms, so they get conjugated as if ending in a consonant.
-- We remove the pseudoconsonant later.
local is_suffix = lemma ~= "-" and rfind(lemma, "^%-")
args.any_suffix = args.any_suffix or is_suffix
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or is_suffix and PSEUDOCONS
if asif_prefix then
lemma = rsub(lemma, "^%-", "-" .. asif_prefix)
if lemmatr then
lemmatr = rsub(lemmatr, "^%-", "-" .. com.translit(asif_prefix))
end
end
args.thisa = args["a" .. n] or args.a
args.thisn = args["n" .. n] or args.n
-- Check for explicit allow-unaccented indication.
local allow_unaccented
lemma, allow_unaccented = rsubb(lemma, "^%*", "")
args.allow_unaccented = args.allow_unaccented or allow_unaccented
if args.allow_unaccented then
track("allow-unaccented")
end
args.orig_lemma = lemma
lemma = m_links.remove_links(lemma)
args.lemma_no_links = lemma
args.lemmatr = lemmatr
if args.lemma then
-- Explicit lemma given.
args.explicit_lemma, args.explicit_lemmatr = com.split_russian_tr(args.lemma)
end
-- Treat suffixes without an accent, and suffixes with an accent on the
-- initial hyphen, as if they were preceded with a *, which overrides
-- all the logic that normally (a) normalizes the accent, and (b)
-- complains about multisyllabic words without an accent. Don't do this
-- if lemma is just -, which is used specially in manual declension
-- tables (e.g. сто, три).
if lemma ~= "-" and (rfind(lemma, "^%-" .. AC) or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
-- Convert lemma and decl arg into stem and canonicalized decl.
-- This will autodetect the declension from the lemma if an explicit
-- decl isn't given.
local stem, tr, gender, was_accented, was_plural, was_autodetected
if rfind(decl, "^%+") then
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
detect_adj_type(lemma, lemmatr, decl, old)
else
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
determine_decl(lemma, lemmatr, decl, args)
end
if was_plural then
args.n = args.orign or "p"
args.thisn = args["n" .. n] or args.n
elseif decl ~= "$" then
args.thisn = args.thisn or "b"
end
args.explicit_gender = gender
-- If allow-unaccented not given, maybe check for missing accents.
if not args.allow_unaccented and not stress_arg and was_autodetected and com.needs_accents(lemma) then
-- If user gave the full word and expects us to determine the
-- declension and stress, the word should have an accent on the
-- stem or ending. We have a separate check farther below for
-- an accent on a multisyllabic stem, after stripping off any
-- ending; but this way we get an error if the user e.g. writes
-- "гора" without an accent rather than assuming it's stem
-- stressed, as would otherwise happen.
error("Lemma must have an accent in it: " .. lemma)
end
-- If stress not given, auto-determine; else validate/canonicalize
-- stress arg, override in certain cases and convert to list.
if not stress_arg then
stress_arg = {detect_stress_pattern(stem, decl, decl_cats, args.reducible, was_plural, was_accented)}
else
stress_arg = rsplit(stress_arg, ",")
for i=1,#stress_arg do
local stress = stress_arg[i]
stress = override_stress_pattern(decl, stress)
if not stress_patterns[stress] then
error("Unrecognized accent pattern " .. stress)
end
stress_arg[i] = stress
end
end
-- parse slash decl to list
local sub_decls
if rfind(decl, "/") then
track("mixed-decl")
insert_cat("~ with mixed declension")
local indiv_decls = rsplit(decl, "/")
-- Should have been caught in canonicalize_decl()
assert(#indiv_decls == 2)
sub_decls = {{indiv_decls[1], "sg"}, {indiv_decls[2], "pl"}}
else
sub_decls = {{decl}}
end
-- Get singular declension and corresponding category.
local sgdecl = sub_decls[1][1]
local sgdc = decl_cats[sgdecl]
assert(sgdc)
-- Compute headword gender(s). We base it off the singular declension
-- if we have a slash declension -- it's the best we can do.
determine_headword_gender(args, sgdc, gender)
local original_stem, original_tr = stem, tr
local original_pl, original_pltr = pl, pltr
-- Loop over accent patterns in case more than one given.
for _, stress in ipairs(stress_arg) do
args.suffixes = {}
stem, tr = original_stem, original_tr
local bare, baretr
local stem_for_bare, tr_for_bare
pl, pltr = original_pl, original_pltr
insert_if_not(all_stresses_seen, stress)
local stem_was_unstressed = com.is_unstressed(stem)
-- If special case ;ё was given and stem is unstressed,
-- add ё to the stem now; but don't let this interfere with
-- restressing, to handle cases like железа́ with gen pl желёз
-- but nom pl же́лезы.
if stem_was_unstressed and args.jo_special then
-- Beware, Cyrillic еЕ in first rsub, Latin eE in second
local new_stem = rsub(stem, "([еЕ])([^еЕ]*)$",
function(e, rest)
return (e == "Е" and "Ё" or "ё") .. rest
end
)
if stem == new_stem then
error("No е in stem to replace with ё")
end
stem = new_stem
if tr then
local subbed
-- e after j -> o, e not after j -> jo; don't just convert e -> jo
-- and then map jjo -> jo because we want to preserve double j
tr, subbed = rsubb(tr, "([jJ])([eE])([^eE]*)$",
function(j, e, rest)
return j .. (e == "E" and "O" or "o") .. AC .. rest
end
)
if not subbed then
tr = rsub(tr, "([eE])([^eE]*)$",
function(e, rest)
return (e == "E" and "Jo" or "jo") .. AC .. rest
end
)
end
tr = com.j_correction(tr)
end
-- This is used to handle железа́ with gen pl желёз and nom pl
-- же́лезы. We have two stressed stems, one for the gen pl and
-- one for the remaining pl cases, and the variable 'stem' can
-- handle only one, so we put the second (gen pl) stem in
-- stem_for_bare, which goes into the value of 'bare' (used
-- only for gen pl here).
stem_for_bare, tr_for_bare = stem, tr
end
-- Maybe add stress to the stem, depending on whether the
-- stem was unstressed and the stress pattern. Stem pattern f
-- and variants call for initial stress (голова́ -> го́ловы);
-- stem pattern d and variants call for stem-final stress
-- (сапожо́к -> сапо́жки). Stem patterns b and b' apparently
-- call for stem-final stress as well but it's unlikely to
-- make much of a difference (pattern b' only occurs in 3rd-decl
-- feminines, which should already have stress in the stem,
-- and the only place pattern b gets stem stress is in bare
-- forms, i.e. nom sg and/or gen pl depending on the decl type,
-- and nom sg stress should already be in the lemma while
-- gen pl stress is handled by a different ending-stressing
-- mechanism in attach_unstressed(); however, the user is
-- free to leave a masc or 3rd-decl fem lemma completely
-- unstressed with pattern b, and then the stem-final stress
-- *will* make a difference).
local function restress_stem(stem, tr, stress, stem_unstressed)
-- If the user has indicated they purposely are leaving the
-- word unstressed by putting a * at the beginning of the main
-- stem, leave it unstressed. This might indicate lack of
-- knowledge of the stress or a truly unaccented word
-- (e.g. an unaccented suffix).
if args.allow_unaccented then
return stem, tr
end
if tr and com.is_unstressed(stem) ~= com.is_unstressed(tr) then
error("Stem " .. stem .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(stem) then
stem, tr = com.make_ending_stressed(stem, tr)
-- For those patterns that are ending-stressed in the singular
-- nominative (and hence are likely to be expressed without an
-- accent on the stem) it's safe to put a particular accent on
-- the stem depending on the stress type. Otherwise, give an
-- error if no accent.
elseif stem_unstressed then
if rfind(stress, "^f") then
stem, tr = com.make_beginning_stressed(stem, tr)
elseif (rfind(stress, "^[bd]") or
args.thisn == "p" and ending_stressed_pl_patterns[stress]) then
stem, tr = com.make_ending_stressed(stem, tr)
elseif com.needs_accents(stem) then
error("Stem " .. stem .. " requires an accent")
end
end
return stem, tr
end
stem, tr = restress_stem(stem, tr, stress, stem_was_unstressed)
-- Leave pl unaccented if user wants this; see restress_stem().
if pl and not args.allow_unaccented then
if pltr and com.is_unstressed(pl) ~= com.is_unstressed(pltr) then
error("Plural stem " .. pl .. " and translit " .. pltr .. " must have same accent pattern")
end
if com.is_monosyllabic(pl) then
pl, pltr = com.make_ending_stressed(pl, pltr)
end
-- I think this is safe.
if com.needs_accents(pl) then
if ending_stressed_pl_patterns[stress] then
pl, pltr = com.make_ending_stressed(pl, pltr)
elseif not args.allow_unaccented then
error("Plural stem " .. pl .. " requires an accent")
end
end
end
local resolved_bare, resolved_baretr
-- Handle (de)reducibles
-- FIXME! We are dereducing based on the singular declension.
-- In a slash declension things can get weird and we don't
-- handle that. We are also computing the bare value from the
-- singular stem, and again things can get weird with a plural
-- stem. Note that we don't compute a bare value unless we have
-- to (either (de)reducible or stress pattern f/f'/f'' combined
-- with ё special case); the remaining times we generate the bare
-- value directly from the plural stem.
if args.reducible and not sgdc.ignore_reduce then
-- Zaliznyak treats all nouns in -ье and -ья as being
-- reducible. We handle this automatically and don't require
-- the user to specify this, but ignore it if so for
-- compatibility.
if is_reducible(sgdc) then
-- If we derived the stem from a nom pl form, then
-- it's already reduced, and we need to dereduce it to
-- get a bare form; otherwise the stem comes from the
-- nom sg and we need to reduce it to get the real stem.
if was_plural then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
resolved_bare, resolved_baretr = stem, tr
stem, tr = export.reduce_nom_sg_stem(stem, tr,
sgdecl, args.soft_n, "error")
-- Stem will be unstressed if stress was on elided
-- vowel; restress stem the way we did above. (This is
-- needed in at least one word, сапожо́к 3*d(2), with
-- plural stem probably сапо́жк- and gen pl probably
-- сапо́жек.)
stem, tr = restress_stem(stem, tr, stress,
com.is_unstressed(stem))
if stress ~= "a" and stress ~= "b" and args.alt_gen_pl and not pl then
-- Nouns like рожо́к, глазо́к of type 3*d(2) have
-- gen pl's ро́жек, гла́зок; to handle this,
-- dereduce the reduced stem and store in a
-- special place.
args.gen_pl_bare, args.gen_pl_baretr =
export.dereduce_nom_sg_stem(stem, tr,
sgdc, stress, old, "error")
end
end
elseif is_dereducible(sgdc) then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
error("Declension class " .. sgdecl .. " not (de)reducible")
end
elseif stem_for_bare and stem ~= stem_for_bare then
resolved_bare, resolved_baretr =
add_bare_suffix(stem_for_bare, tr_for_bare, old, sgdc, false)
end
-- Leave unaccented if user wants this; see restress_stem().
-- FIXME, we no longer allow the user to specify the bare value
-- so it's unclear if this is needed any more.
if resolved_bare and not args.allow_unaccented then
if resolved_baretr and com.is_unstressed(resolved_bare) ~= com.is_unstressed(resolved_baretr) then
error("Resolved bare stem " .. resolved_bare .. " and translit " .. resolved_baretr .. " must have same accent pattern")
end
if com.is_monosyllabic(resolved_bare) then
resolved_bare, resolved_baretr =
com.make_ending_stressed(resolved_bare, resolved_baretr)
else
if com.needs_accents(resolved_bare) then
error("Resolved bare stem " .. resolved_bare .. " requires an accent")
end
end
end
args.stem, args.stemtr = stem, tr
args.bare, args.baretr = resolved_bare, resolved_baretr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, tr)
if pl then
args.pl, args.pltr = pl, pltr
else
args.pl, args.pltr = stem, tr
end
args.upl, args.upltr = com.make_unstressed_once(args.pl, args.pltr)
-- Special hack for любо́вь and other reducible 3rd-fem nouns,
-- which have the full stem in the ins sg
args.ins_sg_stem = sgdecl == "ь-f" and args.reducible and resolved_bare
args.ins_sg_tr = sgdecl == "ь-f" and args.reducible and resolved_baretr
-- Loop over declension classes (we may have two of them, one for
-- singular and one for plural, in the case of a mixed declension
-- class of the form SGDECL/PLDECL).
for _,decl_spec in ipairs(sub_decls) do
local orig_decl = decl_spec[1]
local number = decl_spec[2]
local real_decl =
determine_stress_variant(orig_decl, stress)
real_decl = determine_stem_variant(real_decl,
number == "pl" and args.pl or args.stem)
-- sanity checking; errors should have been caught in
-- canonicalize_decl()
assert(decl_cats[real_decl], "real_decl " .. real_decl .. " nonexistent")
assert(decl_sufs[real_decl], "real_decl " .. real_decl .. " nonexistent")
tracking_code(stress, orig_decl, real_decl, args, n, islast)
do_stress_pattern(stress, args, real_decl, number, n, islast)
-- handle internal notes
local internal_note = intable[real_decl]
if internal_note then
insert_if_not(args.internal_notes, internal_note)
end
end
categorize_and_init_heading(stress, decl, args, n, islast)
end
end
local n = 0
for _, word_info in ipairs(per_word_info) do
n = n + 1
local islast = n == #per_word_info
local arg_sets, joiner = word_info[1], word_info[2]
args.forms = {}
args.heading_info = {animacy={}, number={}, gender={}, stress={},
stemetc={}, adjectival={}, reducible={}}
args.categories = {}
args.genders = {}
args.this_any_non_nil = {}
args.any_suffix = false
if #arg_sets > 1 then
track("multiple-arg-sets")
-- insert_cat("~ with multiple argument sets")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
default_lemma = pagename
all_stresses_seen = {}
-- Loop over all arg sets.
for _, arg_set in ipairs(arg_sets) do
do_arg_set(arg_set, n, islast)
end
if #all_stresses_seen > 1 then
track("multiple-accent-patterns")
-- insert_cat("~ with multiple accent patterns")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
table.insert(args.per_word_heading_info, args.heading_info)
table.insert(args.per_word_categories, args.categories)
local headings = compute_heading(args)
table.insert(args.per_word_headings, headings)
table.insert(args.per_word_genders, args.genders)
handle_forms_and_overrides(args, n, islast)
if args.any_suffix then
-- If we're conjugating a suffix, remove the pseudoconsonant or asif_prefix
-- that we previously inserted at the beginning.
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or PSEUDOCONS
local asif_prefix_tr = com.translit(asif_prefix)
for _, case in ipairs(all_cases) do
if args.forms[case] then
local newforms = {}
for _, form in ipairs(args.forms[case]) do
local formru = form[1]
local formtr = form[2]
formru = rsub(formru, "^%-" .. asif_prefix, "-")
if formtr then
formtr = rsub(formtr, "^%-" .. asif_prefix_tr, "-")
end
if formru == "-" then
-- if no ending, insert "(no suffix)".
table.insert(newforms, {"(no suffix)"})
else
table.insert(newforms, {formru, formtr})
end
end
args.forms[case] = newforms
end
end
end
table.insert(args.per_word_info, {args.forms, joiner})
end
handle_overall_forms_and_overrides(args)
compute_overall_heading_categories_and_genders(args)
for _, case in ipairs(all_cases) do
if args[case] then
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
ruentry = m_links.remove_links(ruentry)
if rfind(ulower(ruentry), latin_text_class) then
--error("Found Latin text " .. ruentry .. " in case " .. case)
track("latin-text")
track("latin-text/" .. case)
end
end
end
end
-- Test code to compare existing module to new one.
if test_new_ru_noun_module then
local m_new_ru_noun = require("Module:User:Benwing2/ru-noun")
local newargs = m_new_ru_noun.do_generate_forms(orig_args, old)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
local is_pl = rfind(case, "_pl")
if args.thisn == "s" and is_pl or args.thisn == "p" and not is_pl then
-- Don't need to check cases that won't be displayed.
elseif not m_table.deepEquals(arg, newarg) then
local monosyl_accent_diff = false
-- Differences only in monosyllabic accents. Enable if we
-- change the algorithm for these.
--if arg and newarg and #arg == 1 and #newarg == 1 then
-- local ru1, tr1 = arg[1][1], arg[1][2]
-- local ru2, tr2 = newarg[1][1], newarg[1][2]
-- if com.is_monosyllabic(ru1) and com.is_monosyllabic(ru2) then
-- ru1, tr1 = com.remove_accents(ru1, tr1)
-- ru2, tr2 = com.remove_accents(ru2, tr2)
-- if ru1 == ru2 and tr1 == tr2 then
-- monosyl_accent_diff = true
-- end
-- end
--end
if monosyl_accent_diff then
track("monosyl-accent-diff")
difdecl = true
else
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
end
if not difdecl then track("same-decl") end
end
return args
end
-- Implementation of main entry point
local function do_show(frame, old)
local args = clone_args(frame)
local args = export.do_generate_forms(args, old)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- Implementation of new entry point, esp. for multiple words
local function do_show_multi(frame)
local args = clone_args(frame)
local args = export.do_generate_forms_multi(args)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The new entry point, esp. for multiple words (but works fine for
-- single words).
function export.show_multi(frame)
return do_show_multi(frame)
end
local function get_form(forms, preserve_links, raw)
local canon_forms = {}
for _, form in ipairs(forms) do
if raw then
local ru, tr = form[1], form[2]
ru = rsub(ru, "|", "<!>")
if tr then
tr = rsub(tr, "|", "<!>")
end
insert_if_not(canon_forms, {ru, tr})
else
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
-- Skip hypothetical forms (but include in the raw versions)
if not rfind(runotes, HYPMARKER) then
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
end
if not preserve_links then
ruentry = m_links.remove_links(ruentry)
end
ruentry = rsub(ruentry, "|", "<!>")
if trentry then
trentry = rsub(trentry, "|", "<!>")
end
insert_if_not(canon_forms, {ruentry, trentry})
end
end
end
return com.concat_forms(canon_forms)
end
local function case_will_be_displayed(args, case)
local ispl = rfind(case, "_pl")
local caseok = true
if args.n == "p" then
caseok = ispl
elseif args.n == "s" then
caseok = not ispl
end
for _, override_case in ipairs(overridable_only_cases) do
if case == override_case and not args.any_overridden[override_case] then
caseok = false
break
end
end
if args.a == "a" or args.a == "i" then
if rfind(case, "_[ai]n") then
caseok = false
end
else -- bianimate
-- don't include inanimate/animate variants if combined variant exists
-- (typically because inanimate/animate variants are the same);
-- FIXME: This could conceivably be different from how the display
-- code works, which just checks that the inanimate/animate variants
-- are the same when deciding whether to display them, in particular
-- if there is an override. Here we are following the algorithm of
-- handle_overall_forms_and_overrides().
if (case == "acc_sg_in" or case == "acc_sg_an") and args.acc_sg or
(case == "acc_pl_in" or case == "acc_pl_an") and args.acc_pl then
caseok = false
end
end
if not args[case] then
caseok = false
end
return caseok
end
local function concat_case_args(args, do_all, raw)
local ins_text = {}
for _, case in ipairs(do_all and all_cases or overridable_cases) do
if case_will_be_displayed(args, case) then
local forms = get_form(args[case], rfind(case, "_linked"), raw)
if forms ~= "" then
table.insert(ins_text, case .. (raw and "_raw" or "") .. "=" ..
forms)
end
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-noun-forms' to generate all noun forms.
-- This returns a single string, with | separating arguments and named
-- arguments of the form NAME=VALUE.
function export.generate_forms(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
return concat_case_args(args)
end
-- The entry point to generate multiple sets of noun forms. This is a hack
-- to speed up calling from a bot, where we often want to compare old and new
-- argument results to make sure they're the same. Each set of arguments is
-- jammed together into a single argument with individual values separated by
-- <!>; named arguments are of the form NAME<->VALUE. The return value for
-- each set of arguments is as in export.generate_forms(), and the return
-- values are concatenated with <!> separating them. NOTE: This will fail if
-- the exact sequences <!> or <-> happen to occur in values (which is unlikely,
-- esp. as we don't even use the characters <, ! or > for anything) and aren't
-- HTML-escaped.
function export.generate_multi_forms(frame)
local retvals = {}
for _, argset in ipairs(frame.args) do
local args = {}
local i = 0
local argvals = rsplit(argset, "<!>")
for _, argval in ipairs(argvals) do
local split_arg = rsplit(argval, "<%->")
if #split_arg == 1 then
i = i + 1
args[i] = ine(split_arg[1])
else
assert(#split_arg == 2)
args[split_arg[1]] = ine(split_arg[2])
end
end
args = export.do_generate_forms(args, false)
table.insert(retvals, concat_case_args(args))
end
return table.concat(retvals, "<!>")
end
-- The entry point for 'ru-noun-form' to generate a particular noun form.
function export.generate_form(frame)
local args = clone_args(frame)
if not args.form then
error("Must specify desired form using form=")
end
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
local args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
-- The entry point for generating arguments of various sorts, including
-- the case forms, gender, number and animacy.
function export.generate_args(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
local retargs = {}
table.insert(retargs, concat_case_args(args, "doall"))
table.insert(retargs, concat_case_args(args, "doall", "raw"))
table.insert(retargs, "g=" .. table.concat(args.genders, ","))
-- The following is correct even with ndef because if ndef is
-- set we will set it in args.n.
table.insert(retargs, "n=" .. (args.n or "b"))
table.insert(retargs, "a=" .. (args.a or "i"))
return table.concat(retargs, "|")
end
-- The entry point for compatibility with {{ru-decl-noun-z}}.
function export.show_z(frame)
local args = clone_args(frame)
local stem = args[1]
local stress = args[2]
local specific = args[4] or ""
-- Parse gender/animacy spec
local gender, anim = rmatch(args[3], "^([mfn])-([a-z]+)")
if not gender then
error("Unrecognized gender/anim spec " .. args[3])
end
if anim ~= "an" and anim ~= "in" then anim = "both" end
args.a = anim
-- Handle specific
specific = rsub(specific, "ё", ";ё")
-- Compute decl; special case for семьянин (perhaps not necessary)
local decl = com.make_unstressed_once(stem) == "семьянин" and "#" .. specific or gender .. specific
-- Handle overrides
args.pre_sg = args.prp_sg
args.pre_pl = args.prp_pl
args.notes = args.note
if args.par then
args.par = "+"
end
if args.loc then
if args.loc == "в" then
args.loc = "в +"
elseif args.loc == "на" then
args.loc = "на +"
else
args.loc = "в +,на +"
end
end
local arg_set = {}
table.insert(arg_set, stress)
table.insert(arg_set, stem)
table.insert(arg_set, decl)
local per_word_info = {{{arg_set}, ""}}
return generate_forms_1(args, per_word_info)
end
--------------------------------------------------------------------------
-- Autodetection and lemma munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the stem and the ending. GENDER must be present with -ь and plural
-- stems, and is otherwise ignored. Return up to three values: The stem
-- (lemma minus ending), the singular lemma ending, and if the lemma was
-- plural, the plural lemma ending. If the lemma was singular, the singular
-- lemma ending will contain any user-given accents; likewise, if the
-- lemma was plural, the plural ending will contain such accents.
-- VARIANT comes from the declension spec and controls certain declension
-- variants.
local function detect_lemma_type(lemma, tr, gender, args, variant)
local base, ending = rmatch(lemma, "^(.*)([еЕ]" .. AC .. ")$") -- accented
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([еЕ])$") -- unaccented
if base then
if variant == "-ище" and not rfind(lemma, "[щЩ][еЕ]$") then
error("With declension variant -ище, lemma should end in -ще: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), variant == "-ище" and "(ищ)е-и" or "о"
end
if variant == "-ишко" then
base, ending = rmatch(lemma, "^(.*[шШ][кК])([оО])$") -- unaccented
if not base then
error("With declension variant -ишко, lemma should end in -шко: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), "(ишк)о-и"
end
if variant == "-ин" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$") -- maybe accented
if not base then
error("With declension variant -ин, lemma should end in -ин(ъ): " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
-- Now autodetect -ин; only animate and in -анин/-янин
base, ending = rmatch(lemma, "^(.*[аАяЯ][" .. AC .. GR .. "]?[нН])([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$")
-- Need to check the animacy to avoid nouns like маиганин, цианин,
-- меланин, соланин, etc.
if base and args.thisa == "a" then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([мМ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
--recognize plural endings
if gender == "n" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
-- Don't do this; о/-ья is too rare
-- error("Ambiguous plural lemma " .. lemma .. " in -ья, singular could be -о or -ье/-ьё; specify the singular")
return base, com.strip_tr_ending(tr, ending), "ье", ending
end
base, ending = rmatch(lemma, "^(.*)([аяАЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), rfind(ending, "[аА]") and "о" or "е", ending
end
base, ending = rmatch(lemma, "^(.*)([ыиЫИ][" .. AC .. GR .. "]?)$")
if base then
if rfind(ending, "[ыЫ]") or rfind(base, "[" .. com.sib .. com.velar .. "]$") then
return base, com.strip_tr_ending(tr, ending), "о-и", ending
else
-- FIXME, should we return a slash declension?
error("No neuter declension е-и available; use a slash declension")
end
end
end
if gender == "f" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ья", ending
end
end
-- Recognize masculines with irregular plurals, but only if the user
-- either explicitly specified that this noun is plural (n=p) or
-- specifically requested the irregular plural. This is necessary
-- because some masculine nouns have feminine endings, which look
-- like irregular plurals.
if gender == "m" then
if args.thisn == "p" or variant == "-ья" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-ья" or "-ья"), ending
end
end
if args.thisn == "p" or args.want_sc1 then
base, ending = rmatch(lemma, "^(.*)([аА][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-а" or "-а"), ending
end
base, ending = rmatch(lemma, "^(.*)([яЯ][" .. AC .. GR .. "]?)$")
if base then
if rfind(base, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return base, com.strip_tr_ending(tr, ending), "й-я", ending
else
return base, com.strip_tr_ending(tr, ending), "ь-я", ending
end
end
end
end
if gender == "m" or gender == "f" then
base, ending = rmatch(lemma, "^(.*[" .. com.sib .. com.velar .. "])([иИ][" .. AC .. GR .. "]?)$")
if not base then
base, ending = rmatch(lemma, "^(.*)([ыЫ][" .. AC .. GR .. "]?)$")
end
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and (args.old and "ъ" or "") or "а", ending
end
base, ending = rmatch(lemma, "^(.*[" .. com.vowel .. "й][" .. AC .. GR .. "]?)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "й" or "я", ending
end
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "ь-m" or "я", ending
end
end
if gender == "3f" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ь-f", ending
end
end
-- end of recognize-plurals code
base, ending = rmatch(lemma, "^(.*)([ьЬ][яеёЯЕЁ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([йаяеоёъЙАЯЕОЁЪ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ьЬ])$")
if base then
if gender == "m" or gender == "f" then
return base, com.strip_tr_ending(tr, ending), "ь-" .. gender
elseif gender == "3f" then
return base, com.strip_tr_ending(tr, ending), "ь-f"
else
error("Need to specify gender m or f with lemma in -ь: ".. lemma)
end
end
if rfind(lemma, "[ыиЫИ][" .. AC .. GR .. "]?$") then
error("If this is a plural lemma, gender must be specified: " .. lemma)
elseif rfind(lemma, "[иИіІуУыЫѣѢэЭюЮѵѴ]" .. DIA .. "?[" .. AC .. GR .. "]?$") then
error("Don't know how to decline lemma ending in this type of vowel: " .. lemma)
end
return lemma, tr, ""
end
local plural_variant_detection_map = {
[""] = {["-ья"]="-ья"},
["ъ"] = {["-ья"]="ъ-ья"},
}
local special_case_1_to_plural_variant = {
[""] = "-а",
["ъ"] = "ъ-а",
["й"] = "й-я",
["ь-m"] = "ь-я",
["о"] = "о-и",
-- these last two are here to avoid getting errors in that checks for
-- compatibility with special case 1; the basic variants of these decls
-- don't actually exist
["(ишк)о"] = "(ишк)о-и",
["(ищ)е"] = "(ищ)е-и",
}
local function map_decl(decl, fun)
if rfind(decl, "/") then
local split_decl = rsplit(decl, "/")
if #split_decl ~= 2 then
error("Mixed declensional class " .. decl
.. "needs exactly two classes, singular and plural")
end
return fun(split_decl[1]) .. "/" .. fun(split_decl[2])
else
return fun(decl)
end
end
-- Canonicalize decl class into non-accented and alias-resolved form;
-- but note that some canonical decl class names with an accent in them
-- (e.g. е́, not the same as е, whose accented version is ё; and various
-- adjective declensions).
local function canonicalize_decl(decl, old)
local function do_canon(decl)
-- remove accents, but not from е́ (for adj decls, accent matters
-- as well but we handle that by mapping the accent to a stress pattern
-- and then to the accented version in determine_stress_variant())
if decl ~= "е́" then
decl = com.remove_accents(decl)
end
local decl_aliases = old and declensions_old_aliases or declensions_aliases
local decl_cats = old and declensions_old_cat or declensions_cat
if decl_aliases[decl] then
-- If we find an alias, map it.
decl = decl_aliases[decl]
elseif not decl_cats[decl] then
error("Unrecognized declension class " .. decl)
end
return decl
end
return map_decl(decl, do_canon)
end
-- Attempt to determine the actual declension (including plural variants)
-- based on a combination of the declension the user specified, what can be
-- detected from the lemma, and special case (1), if given in the declension.
-- DECL is the value the user passed for the declension field, after
-- extraneous annotations (special cases (1) and (2), * for reducible,
-- ё for ё/ё alternation and a ; that may precede ё) have been stripped off.
-- What's left is one of the following:
--
-- 1. Blank, meaning to autodetect the declension from the lemma
-- 2. A hyphen followed by a declension variant (-ья, -ин, -ишко, -ище; see
-- long comment at top of file)
-- 3. A gender (m, f, n, 3f)
-- 4. A gender plus declension variant (e.g. f-ья)
-- 5. An actual declension, possibly including a plural variant (e.g. о-и) or
-- a slash declension (e.g. я/-ья, used for the noun дядя).
--
-- Return seven args: stem (lemma minus ending), translit, canonicalized
-- declension, explicitly specified gender if any (m, f, n or nil), whether
-- the specified declension or detected ending was accented, whether the
-- detected ending was pl, and whether the declension was autodetected
-- (corresponds to cases where a full word with ending attached is required
-- in the lemma field). "Canonicalized" means after autodetection, with
-- accents removed, with any aliases mapped to their canonical versions
-- and with any requested declension variants applied. The result is either a
-- declension that will have a categorization entry (in declensions_cat[] or
-- declensions_old_cat[]) or a slash declension where each part similarly has
-- a categorization entry.
--
-- Note that gender is never required when an explicit declension is given,
-- and in connection with stem autodetection is required only when the lemma
-- either ends in -ь or is plural.
determine_decl = function(lemma, tr, decl, args)
-- Assume we're passed a value for DECL of types 1-4 above, and
-- fetch gender and requested declension variant.
local stem
local want_ya_plural, orig_pl_ending, variant
local was_autodetected
local gender = rmatch(decl, "^(3?[mfn]?)$")
if not gender then
gender, variant = rmatch(decl, "^(3?[mfn]?)(%-[^%-]+)$")
-- But be careful with explicit declensions like -а that look like
-- variants without gender (FIXME, eventually we should maybe do
-- something about the potential ambiguity).
if gender == "" and not m_table.contains({"-ья", "-ин", "-ишко", "-ище"}, variant) then
gender, variant = nil, nil
end
end
-- If DECL is of type 1-4, handle declension variants and detect
-- the actual declension from the lemma.
if gender then
-- Check for declension variants
if variant then
if variant == "-ья" then
want_ya_plural = "-ья"
else
-- Sanity-check remaining declension variants, which need
-- specific values of animacy, gender and special-case (1)
local sc1_needed
local animate_needed
if variant == "-ишко" then
animate_needed = false
sc1_needed = true
elseif variant == "-ище" then
animate_needed = true
sc1_needed = true
elseif variant == "-ин" then
animate_needed = true
sc1_needed = false
else
-- WARNING: If adding another variant, you need to also
-- add to the list farther above.
error("Unrecognized declension variant " .. variant .. ", should be -ья, -ин, -ишко or -ище")
end
if sc1_needed and not args.want_sc1 then
error("Declension variant " .. variant .. " must be used with special case (1)")
elseif sc1_needed == false and args.want_sc1 then
error("Declension variant " .. variant .. " must not be used with special case (1)")
end
if animate_needed and args.thisa ~= "a" then
error("Declension variant " .. variant .. " must be specified as animate")
elseif animate_needed == false and args.thisa == "a" then
error("Declension variant " .. variant .. " must not be specified as animate")
end
if gender ~= "" and gender ~= "m" then
error("Declension variant " .. variant .. " should be used with the masculine gender")
end
end
end
stem, tr, decl, orig_pl_ending = detect_lemma_type(lemma, tr, gender,
args, variant)
was_autodetected = true
else
stem, tr = lemma, tr
end
-- Now canonicalize gender
if gender == "3f" then
gender = "f"
elseif gender == "" then
gender = nil
end
-- The ending should be treated as accented if either the original singular
-- or plural ending was accented, or if the stem is non-syllabic.
local was_accented = com.is_stressed(decl) or
orig_pl_ending and com.is_stressed(orig_pl_ending) or
com.is_nonsyllabic(stem)
local was_plural = not not orig_pl_ending
decl = canonicalize_decl(decl, args.old)
-- The rest of this code concerns plural variants. It's somewhat
-- complicated because there are potentially four sources of plural
-- variants (not to mention plural variants constructed using slash
-- notation):
--
-- 1. A user-requested plural variant in declension types 2 or 4 above
-- (currently only -ья)
-- 2. An explicit plural variant encoded in an explicit declension of
-- type 5 above
-- 3. An autodetected plural variant (which will happen in some cases
-- when autodetection is performed on a nominative plural)
-- 4. A plural variant derived using special case (1).
--
-- Up to three actual plural variants might exist (e.g. if the user
-- specifies a DECL value or 'm-ья(1)' and a STEM ending in -а,
-- although not all three can ever be compatible because -ья and (1)
-- are never compatible). We can't have all four because if there's
-- an explicit plural variant, there won't be a user-requested or
-- autodetected plural variant.
--
-- The goal below is to do two things: Check that all available plural
-- variants are the same, and generate the actual declension.
-- If we have a type-2 or type-3 variant, we already have the actual
-- declension; else we need to use a table to map the basic declension
-- to the one with the plural variant encoded in it.
--
-- NOTE: The code below was written with a more general plural-variant
-- system. It probably can be simplified a lot now.
-- 1: Handle explicit decl with slash variant
if rfind(decl, "/") then
if want_ya_plural then
-- Don't think this can happen
error("Plural variant " .. want_ya_plural .. " not compatible with slash declension " .. decl)
end
if args.want_sc1 then
error("Special case (1) not compatible with slash declension" .. decl)
end
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- 2: Retrieve explicitly specified or autodetected decl and pl. variant
local basic_decl, detected_or_explicit_plural = rmatch(decl, "^(.*)(%-[^mf]+)$")
if basic_decl == "ь" then
basic_decl = "ь-m"
end
basic_decl = basic_decl or decl
-- 3: Any user-requested plural variant must agree with explicit or
-- autodetected variant.
if want_ya_plural and detected_or_explicit_plural and want_ya_plural ~= detected_or_explicit_plural then
error("Plural variant " .. want_ya_plural .. " requested but plural variant " .. detected_or_explicit_plural .. " detected from plural stem")
end
-- 4: Handle special case (1). Derive the full declension, make sure its
-- plural variant matches any other available plural variants, and
-- return the declension.
if args.want_sc1 then
local sc1_decl = special_case_1_to_plural_variant[basic_decl] or
error("Special case (1) not compatible with declension " .. basic_decl)
local sc1_plural = rsub(sc1_decl, "^.*%-", "-")
local other_plural = want_ya_plural or detected_or_explicit_plural
if other_plural and sc1_plural ~= other_plural then
error("Plural variant " .. other_plural .. " specified or detected, but special case (1) calls for plural variant " .. sc1_plural)
end
return stem, tr, sc1_decl, gender, was_accented, was_plural, was_autodetected
end
-- 5: Handle user-requested plural variant without explicit or detected
-- one. (If an explicit or detected one exists, we've already checked
-- that it agrees with the user-requested one, and so we already have
-- our full declension.)
if want_ya_plural and not detected_or_explicit_plural then
local variant_decl
if plural_variant_detection_map[decl] then
variant_decl = plural_variant_detection_map[decl][want_ya_plural]
end
if variant_decl then
return stem, tr, variant_decl, gender, was_accented, was_plural, was_autodetected
else
return stem, tr, decl .. (args.old and "/ъ-ья" or "/-ья"), gender, was_accented, was_plural, was_autodetected
end
end
-- 6: Just return the full declension, which will include any available
-- plural variant in it.
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- Convert soft adjectival declensions into hard ones following certain
-- stem-final consonants. FIXME: We call this in two places, once
-- to handle auto-detection and once to handle explicit declensions; but
-- in the former case we end up calling it twice.
local function determine_adj_stem_variant(decl, stem)
local iend = rmatch(decl, "^%+[іи]([йея]?)$")
-- Convert ій/ий to ый after velar or sibilant. This is important for
-- velars; doesn't really matter one way or the other for sibilants as
-- the sibilant rules will convert both sets of endings to the same
-- thing (whereas there will be a difference with о vs. е for velars).
if iend and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl = "+ы" .. iend
-- The following is necessary for -ц, unclear if makes sense for
-- sibilants. (Would be necessary -- I think -- if we were
-- inferring short adjective forms, but we're not.)
elseif decl == "+ее" and rfind(stem, "[" .. com.sib_c .. "]$") then
decl = "+ое"
end
return decl
end
-- Attempt to determine the actual adjective declension based on a
-- combination of the declension the user specified and what can be detected
-- from the stem. DECL is the value the user passed for the declension field,
-- after extraneous annotations have been removed (although none are probably
-- relevant here). What's left is one of the following, which always begins
-- with +:
--
-- 1. +, meaning to autodetect the declension from the stem
-- 2. +ь, same as + but selects +ьий instead of +ий if lemma ends in -ий
-- 3. +short, +mixed or +proper, with the declension partly specified but
-- the particular gender/number-specific short/mixed variant to be
-- autodetected
-- 4. A gender (+m, +f or +n), used only for detecting the singular of
-- plural-form lemmas (this is primarily used in conjunction with template
-- ru-noun+, to explicitly specify the gender; for the actual declension,
-- it doesn't much matter what singular gender we pick since we're a
-- plural only)
-- 5. A gender plus short/mixed/proper/ь (e.g. +f-mixed), again with the gender
-- used only for detecting the singular of plural-form short/mixed lemmas
-- 6. An actual declension, possibly including a slash declension
-- (WARNING: Unclear if slash declensions will work, especially those
-- that are adjective/noun combinations)
--
-- Returns the same seven args as for determine_decl(). The returned
-- declension will always begin with +.
detect_adj_type = function(lemma, tr, decl, old)
local was_autodetected
local base, ending
local basedecl, g = rmatch(decl, "^(%+)([mfn])$")
if not basedecl then
g, basedecl = rmatch(decl, "^%+([mfn])%-([a-zь]+)$")
if basedecl then
basedecl = "+" .. basedecl
end
end
decl = basedecl or decl
if decl == "+" or decl == "+ь" then
local loc = rfind(lemma, "[аеиіоыя][" .. AC .. GR .. "]?[йея]$") or rfind(lemma, "ь[йея]$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
end
if ending == "ий" and decl == "+ь" then
decl = "+ьий"
elseif ending == "ій" and decl == "+ь" then
decl = "+ьій"
elseif ending then
decl = "+" .. ending
else
local loc, shortmixed = rfind(lemma, "[аоы][" .. AC .. GR .. "]?$") or rfind(lemma, "ъ?$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
shortmixed = rfind(base, "^[" .. com.uppercase .. "].*[иы]" .. AC .. "н$") and "stressed-proper" or -- accented
rfind(base, "^[" .. com.uppercase .. "].*[иы]н$") and "proper" or --not accented
rlfind(base, "[ёео][" .. AC .. GR .. "]?в$") and "short" or
rlfind(base, "[ыи]" .. AC .. "н$") and "stressed-short" or -- accented
rlfind(base, "[ыи]н$") and "mixed" --not accented
end
if not shortmixed then
error("Cannot determine stem type of adjective: " .. lemma)
end
decl = "+" .. ending .. "-" .. shortmixed
end
was_autodetected = true
elseif m_table.contains({"+short", "+mixed", "+proper"}, decl) then
base, ending = rmatch(lemma, "^(.-)([оаыъ]?[" .. AC .. GR .. "]?)$")
assert(base)
local shortmixed = usub(decl, 2)
if rlfind(base, "[ыи]" .. AC .. "н$") then -- accented
if shortmixed == "short" then shortmixed = "stressed-short"
elseif shortmixed == "proper" then shortmixed = "stressed-proper"
end
end
decl = "+" .. ending .. "-" .. shortmixed
was_autodetected = true
else
base = lemma
end
if ending and ending ~= "" then
tr = com.strip_tr_ending(tr, ending)
end
-- Remove any accents from the declension, but not their presence.
-- We will convert was_accented into stress pattern b, and convert that
-- back to an accented version in determine_stress_variant(). This way
-- we end up with the stressed version whether the user placed an accent
-- in the ending or decl or specified stress pattern b.
-- FIXME, might not work in the presence of slash declensions
local was_accented = com.is_stressed(decl)
decl = com.remove_accents(decl)
decl = map_decl(decl, function(decl)
return determine_adj_stem_variant(decl, base)
end)
local singdecl
if decl == "+ые" then
singdecl = (g == "m" or not g) and (was_accented and "+ой" or "+ый") or not old and g == "f" and "+ая" or not old and g == "n" and "+ое"
elseif decl == "+ыя" and old then
singdecl = (g == "f" or not g) and "+ая" or g == "n" and "+ое"
elseif decl == "+ие" and not old then
singdecl = (g == "m" or not g) and "+ий" or g == "f" and "+яя" or g == "n" and "+ее"
elseif decl == "+іе" and old and (g == "m" or not g) then
singdecl = "+ій"
elseif decl == "+ія" and old then
singdecl = (g == "f" or not g) and "+яя" or g == "n" and "+ее"
elseif decl == "+ьи" then
singdecl = (g == "m" or not g) and (old and "+ьій" or "+ьий") or g == "f" and "+ья" or g == "n" and "+ье"
elseif rfind(decl, "^%+ы%-") then -- decl +ы-mixed or similar
local beg = (g == "m" or not g) and (old and "ъ" or "") or g == "f" and "а" or g == "n" and "о"
singdecl = beg and "+" .. beg .. usub(decl, 3)
end
if singdecl then
was_plural = true
decl = singdecl
end
return base, tr, canonicalize_decl(decl, old), g, was_accented, was_plural, was_autodetected
end
-- If stress pattern omitted, detect it based on whether ending is stressed
-- or the decl class or stem accent calls for inherent stress, defaulting to
-- pattern a. This is run after alias resolution and accent removal of DECL;
-- WAS_ACCENTED indicates whether the ending was originally stressed.
-- FIXME: This is run before splitting slash patterns but should be run after.
detect_stress_pattern = function(stem, decl, decl_cats, reducible,
was_plural, was_accented)
-- ёнок and ёночек always bear stress
if rfind(decl, "ёнокъ?") or rfind(decl, "ёночекъ?") then
return "b"
-- stressed suffix и́н; missing in plural and true endings don't bear stress
-- (except for exceptional господи́н)
elseif rfind(decl, "инъ?") and was_accented then
return "d"
-- Adjectival -ой always bears the stress
elseif rfind(decl, "%+ой") then
return "b"
-- Adjectival stressed-short, stressed-proper bears the stress
elseif rfind(decl, "^%+.*%-stressed") then
return "b"
-- Pattern b if ending was accented by user
elseif was_accented then
return "b"
-- Nonsyllabic stem means pattern b
elseif com.is_nonsyllabic(stem) then
return "b"
-- Accent on reducible vowel in masc nom sg (not plural) means pattern b.
-- Think about whether we want to enable this.
-- elseif reducible and not was_plural then
-- -- FIXME hack. Eliminate plural part of slash declension.
-- decl = rsub(decl, "/.*", "")
-- if decl_cats[decl] and decl_cats[decl].g == "m" then
-- if com.is_ending_stressed(stem) or com.is_monosyllabic(stem) then
-- return "b"
-- end
-- end
end
return "a"
end
-- In certain special cases, depending on the declension, we override the
-- user-specified stress pattern and convert it to something else.
-- NOTE: This function is run after alias resolution and accent removal.
-- FIXME: It's also run before splitting slash patterns but should be run after.
override_stress_pattern = function(decl, stress)
-- ёнок and ёночек always bear stress; if user specified a,
-- convert to b. Don't do this with slash patterns (see FIXME above).
if stress == "a" and (rfind(decl, "^ёнокъ?$") or rfind(decl, "^ёночекъ?$")) then
return "b"
end
return stress
end
-- Canonicalize an adjectival declension to either the stressed or unstressed
-- variant depending on the stress. Ultimately this is what ensures that
-- the user's stress mark on an adjectival ending is respected.
determine_stress_variant = function(decl, stress)
if stress == "b" then
if decl == "+ая" then
return "+а́я"
elseif decl == "+ое" then
return "+о́е"
else
-- Convert +...-short to +...-stressed-short and same for -proper
local b, e = rmatch(decl, "^%+(.*)%-(short)$")
if not b then
b, e = rmatch(decl, "^%+(.*)%-(proper)$")
end
if b and not rfind(b, "%-stressed") then
return "+" .. b .. "-stressed-" .. e
end
end
end
return decl
end
-- Canonicalize a declension based on the final stem consonant, in
-- particular converting soft declensions to hard ones after velars and/or
-- sibilants. FIXME: We also do this canonicalization earlier on during
-- auto-detection (determine_adj_stem_variant() is called by
-- detect_adj_type(), and code in detect_lemma_type() does the equivalent
-- of the first clause below). Doing it here ensures that explicitly
-- specified declensions get handled as well, but it would be nice to not
-- do the same thing twice in the auto-detection case.
determine_stem_variant = function(decl, stem)
if decl == "е" and rfind(stem, "[" .. com.sib_c .. "]$") then
return "о"
end
return determine_adj_stem_variant(decl, stem)
end
is_reducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "3rd" and decl_cat.g == "f" or decl_cat.g == "m" then
return true
else
return false
end
end
-- Reduce nom sg to stem by eliminating the "epenthetic" vowel. Applies to
-- masculine 2nd-declension hard and soft, and 3rd-declension feminine in
-- -ь. STEM and DECL are after determine_decl(), before converting
-- outward-facing declensions to inward ones.
function export.reduce_nom_sg_stem(stem, tr, decl, soft_n, can_err)
local full_stem = stem .. (decl == "й" and decl or "")
local full_tr = tr and tr .. (decl == "й" and "j" or "")
local ret, rettr = com.reduce_stem(full_stem, full_tr, soft_n)
if not ret and can_err then
error("Unable to reduce stem " .. stem)
end
return ret, rettr
end
is_dereducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "1st" or decl_cat.decl == "2nd" and decl_cat.g == "n" then
return true
else
return false
end
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. dereducible nouns
-- in -ня.
add_bare_suffix = function(bare, baretr, old, sgdc, dereduced)
if old and sgdc.hard == "hard" then
-- Final -ъ isn't transliterated
return bare .. "ъ", baretr
elseif sgdc.hard == "soft" or sgdc.hard == "palatal" then
-- This next clause corresponds to a special case in Vitalik's module.
-- It says that nouns in -ня (accent class a) have gen pl without
-- trailing -ь. It appears to apply to most nouns in -ня (possibly
-- all in -льня), but ку́хня (gen pl ку́хонь) and дерéвня (gen pl
-- дереве́нь) is an exception. (Vitalik's module has an extra
-- condition here 'stress == "a"' that would exclude дере́вня but I
-- don't think this condition is in Zaliznyak, as he indicates
-- дере́вня as having an exceptional genitive plural.)
if dereduced and rfind(bare, "[нН]$") and sgdc.decl == "1st" then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
-- Final -ъ isn't transliterated
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return bare .. "й", baretr and (baretr .. "j")
else
return bare .. "ь", baretr and (baretr .. "ʹ")
end
else
return bare, baretr
end
end
-- Dereduce stem to the form found in the gen pl (and maybe nom sg) by
-- inserting an epenthetic vowel. Applies to 1st declension and 2nd
-- declension neuter, and to 2nd declension masculine when the stem was
-- specified as a plural form (in which case we're deriving the nom sg,
-- and also the gen pl in the alt-gen-pl scenario). STEM and DECL are
-- after determine_decl(), before converting outward-facing declensions
-- to inward ones. STRESS is the stess pattern.
function export.dereduce_nom_sg_stem(stem, tr, sgdc, stress, old, can_err)
local epenthetic_stress = ending_stressed_gen_pl_patterns[stress]
local ret, rettr = com.dereduce_stem(stem, tr, epenthetic_stress)
if not ret then
if can_err then
error("Unable to dereduce stem " .. stem)
else
return nil, nil
end
end
return add_bare_suffix(ret, rettr, old, sgdc, true)
end
--------------------------------------------------------------------------
-- Second-declension masculine --
--------------------------------------------------------------------------
----------------- Masculine hard -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style).
declensions_old["ъ"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and "е́й" or "о́въ"
end,
["alt_gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["ъ"] = { decl="2nd", hard="hard", g="m" }
-- Normal mapping of old ъ would be "" (blank), but we set up "#" as an alias
-- so we have a way of referring to it without defaulting if need be and
-- distinct from auto-detection (e.g. in the second stem of a word, or to
-- override autodetection of -ёнок or -ин -- the latter is necessary in the
-- case of семьянин).
declensions_aliases["#"] = ""
----------------- Masculine hard, irregular plural -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg nom pl -а.
declensions_old["ъ-а"] = mw.clone(declensions_old["ъ"])
declensions_old["ъ-а"]["nom_pl"] = "а́"
declensions_old_cat["ъ-а"] = { decl="2nd", hard="hard", g="m", alt_nom_pl=true }
declensions_aliases["#-a"] = "-a"
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg soft pl -ья.
-- Differs from the normal declension throughout the plural.
declensions_old["ъ-ья"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = "ьёвъ",
["alt_gen_pl"] = "е́й",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ъ-ья"] = { decl="2nd", hard="hard", g="m", irregpl=true }
declensions_aliases["#-ья"] = "-ья"
----------------- Masculine hard, suffixed, irregular plural -------------------
declensions_old["инъ"] = {
["nom_sg"] = "и́нъ",
["gen_sg"] = "и́на",
["dat_sg"] = "и́ну",
["acc_sg"] = nil,
["ins_sg"] = "и́номъ",
["pre_sg"] = "и́нѣ",
["nom_pl"] = "е́",
["gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["инъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old["ёнокъ"] = {
["nom_sg"] = "ёнокъ",
["gen_sg"] = "ёнка",
["dat_sg"] = "ёнку",
["acc_sg"] = nil,
["ins_sg"] = "ёнкомъ",
["pre_sg"] = "ёнкѣ",
["nom_pl"] = "я́та",
["gen_pl"] = "я́тъ",
["dat_pl"] = "я́тамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тами",
["pre_pl"] = "я́тахъ",
}
declensions_old_cat["ёнокъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["онокъ"] = "ёнокъ"
declensions_old_aliases["енокъ"] = "ёнокъ"
declensions_old["ёночекъ"] = {
["nom_sg"] = "ёночекъ",
["gen_sg"] = "ёночка",
["dat_sg"] = "ёночку",
["acc_sg"] = nil,
["ins_sg"] = "ёночкомъ",
["pre_sg"] = "ёночкѣ",
["nom_pl"] = "я́тки",
["gen_pl"] = "я́токъ",
["dat_pl"] = "я́ткамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тками",
["pre_pl"] = "я́ткахъ",
}
declensions_old_cat["ёночекъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["оночекъ"] = "ёночекъ"
declensions_old_aliases["еночекъ"] = "ёночекъ"
----------------- Masculine soft -------------------
-- Normal soft-masculine declension in -ь
declensions_old["ь-m"] = {
["nom_sg"] = "ь",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["alt_gen_pl"] = "ь",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-m"] = { decl="2nd", hard="soft", g="m" }
-- Soft-masculine declension in -ь with irreg nom pl -я
declensions_old["ь-я"] = mw.clone(declensions_old["ь-m"])
declensions_old["ь-я"]["nom_pl"] = "я́"
declensions_old_cat["ь-я"] = { decl="2nd", hard="soft", g="m", alt_nom_pl=true }
----------------- Masculine palatal -------------------
-- Masculine declension in palatal -й
declensions_old["й"] = {
["nom_sg"] = "й",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = "ёвъ",
["alt_gen_pl"] = "й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["й"] = { decl="2nd", hard="palatal", g="m" }
declensions_old["й-я"] = mw.clone(declensions_old["й"])
declensions_old["й-я"]["nom_pl"] = "я́"
declensions_old_cat["й-я"] = { decl="2nd", hard="palatal", g="m", alt_nom_pl=true }
--------------------------------------------------------------------------
-- First-declension feminine --
--------------------------------------------------------------------------
----------------- Feminine hard -------------------
-- Hard-feminine declension in -а
declensions_old["а"] = {
["nom_sg"] = "а́",
["gen_sg"] = "ы́",
["dat_sg"] = "ѣ́",
["acc_sg"] = "у́",
["ins_sg"] = {"о́й<insa>", "о́ю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["а"] = { decl="1st", hard="hard", g="f" }
----------------- Feminine soft -------------------
-- Soft-feminine declension in -я
declensions_old["я"] = {
["nom_sg"] = "я́",
["gen_sg"] = "и́",
["dat_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_dat_sg_patterns[stress] and "и" or "ѣ́"
end,
["acc_sg"] = "ю́",
["ins_sg"] = {"ёй<insa>", "ёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "]́?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["я"] = { decl="1st", hard="soft", g="f" }
-- Soft-feminine declension in -ья.
-- Almost like ь + -я endings except for genitive plural.
declensions_old["ья"] = {
["nom_sg"] = "ья́",
["gen_sg"] = "ьи́",
["dat_sg"] = "ьѣ́",
["acc_sg"] = "ью́",
["ins_sg"] = {"ьёй<insa>", "ьёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ьи́",
["gen_pl"] = function(stem, stress)
-- circumflex accent is a signal that forces stress, particularly
-- in accent pattern d/d'.
return (ending_stressed_gen_pl_patterns[stress] or stress == "d" or stress == "d'") and "е̂й" or "ий"
end,
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ья"] = {
decl="1st", hard="soft", g="f",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
--------------------------------------------------------------------------
-- Second-declension neuter --
--------------------------------------------------------------------------
----------------- Neuter hard -------------------
-- Normal hard-neuter declension in -о
declensions_old["о"] = {
["nom_sg"] = "о́",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "о́" or nil
end,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "а́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "о́въ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["о"] = { decl="2nd", hard="hard", g="n" }
-- Hard-neuter declension in -о with irreg nom pl -и
declensions_old["о-и"] = mw.clone(declensions_old["о"])
declensions_old["о-и"]["nom_pl"] = "ы́"
declensions_old_cat["о-и"] = { decl="2nd", hard="hard", g="n", alt_nom_pl=true }
declensions_old_aliases["о-ы"] = "о-и"
-- Masculine-gender neuter-form declension in -(ишк)о with irreg nom pl -и,
-- with colloquial feminine endings in some of the singular cases
-- (§5 p. 74 of Zaliznyak)
declensions_old["(ишк)о-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ишк)о-и"]["gen_sg"] = {"а́", "ы́1"}
declensions_old["(ишк)о-и"]["dat_sg"] = {"у́", "ѣ́1"}
declensions_old["(ишк)о-и"]["ins_sg"] = {"о́мъ", "о́й1"}
declensions_old_cat["(ишк)о-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ишк)о-и"] = "<sup>1</sup> Colloquial."
-- Masculine-gender animate neuter-form declension in -(ищ)е with irreg
-- nom pl -и, with colloquial feminine endings in some of the singular cases
-- (§4 p. 74 of Zaliznyak)
declensions_old["(ищ)е-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ищ)е-и"]["acc_sg"] = {"а́", "у́1"}
declensions_old["(ищ)е-и"]["gen_sg"] = {"а́", "ы́2"}
declensions_old["(ищ)е-и"]["dat_sg"] = {"у́", "ѣ́2"}
declensions_old["(ищ)е-и"]["ins_sg"] = {"о́мъ", "о́й2"}
declensions_old_cat["(ищ)е-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ищ)е-и"] = "<sup>1</sup> Colloquial.<br /><sup>2</sup> Less common, more colloquial."
----------------- Neuter soft -------------------
-- Soft-neuter declension in -е (stressed -ё)
declensions_old["е"] = {
["nom_sg"] = "ё",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ё" or nil
end,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е"] = {
singular = function(suffix)
if suffix == "ё" then
return "ending in -ё"
else
return {}
end
end,
decl="2nd", hard="soft", g="n", gensg=true
}
-- User-facing declension type "ё" = "е"
declensions_old_aliases["ё"] = "е"
-- Rare soft-neuter declension in stressed -е́ (e.g. муде́, бытие́)
declensions_old["е́"] = {
["nom_sg"] = "е́",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "е́" or nil
end,
["ins_sg"] = "е́мъ",
["pre_sg"] = function(stem, stress)
-- FIXME!!! Are we sure about this condition? This is what was
-- found in the old template, but the related -е declension has
-- -ие prep sg ending -(и)и only when *not* stressed.
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and "и́" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "й" or "е́й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е́"] = {
singular = "ending in stressed -е",
decl="2nd", hard="soft", g="n", gensg=true
}
-- Soft-neuter declension in unstressed -ье (stressed -ьё).
declensions_old["ье"] = {
["nom_sg"] = "ьё",
["gen_sg"] = "ья́",
["dat_sg"] = "ью́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ьё" or nil
end,
["ins_sg"] = "ьёмъ",
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and "е́й" or "ий"
end,
["alt_gen_pl"] = "ьёвъ",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ье"] = {
decl="2nd", hard="soft", g="n",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
declensions_old_aliases["ьё"] = "ье"
--------------------------------------------------------------------------
-- Third declension --
--------------------------------------------------------------------------
declensions_old["ь-f"] = {
["nom_sg"] = "ь",
["gen_sg"] = "и́",
["dat_sg"] = "и́",
["acc_sg"] = "ь",
["ins_sg"] = "ью́",
["pre_sg"] = "и́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-f"] = { decl="3rd", hard="soft", g="f" }
declensions_old["мя"] = {
["nom_sg"] = "мя",
["gen_sg"] = "мени",
["dat_sg"] = "мени",
["acc_sg"] = nil,
["ins_sg"] = "менемъ",
["pre_sg"] = "мени",
["nom_pl"] = "мена́",
["gen_pl"] = "мёнъ",
["dat_pl"] = "мена́мъ",
["acc_pl"] = nil,
["ins_pl"] = "мена́ми",
["pre_pl"] = "мена́хъ",
}
declensions_old_cat["мя"] = { decl="3rd", hard="soft", g="n", cant_reduce=true }
--------------------------------------------------------------------------
-- Indeclinable --
--------------------------------------------------------------------------
-- Indeclinable declension; no endings.
declensions_old["$"] = {
["nom_sg"] = "",
["gen_sg"] = "",
["dat_sg"] = "",
["acc_sg"] = nil,
["ins_sg"] = "",
["pre_sg"] = "",
["nom_pl"] = "",
["gen_pl"] = "",
["dat_pl"] = "",
["acc_pl"] = nil,
["ins_pl"] = "",
["pre_pl"] = "",
}
declensions_old_cat["$"] = { decl="indeclinable", hard="none", g="none" }
--------------------------------------------------------------------------
-- Adjectival --
--------------------------------------------------------------------------
-- This needs to be up here because it is called just below.
local function old_to_new(v)
v = rsub(v, "ъ$", "")
v = rsub(v, "^ъ", "")
v = rsub(v, "(%A)ъ", "%1")
v = rsub(v, "ъ(%A)", "%1")
v = rsub(v, "і", "и")
v = rsub(v, "ѣ", "е")
return v
end
-- Meaning of entry is:
-- 1. The declension name in module ru-adjective
-- 2. The masculine declension name in this module
-- 3. The neuter declension name in this module
-- 4. The feminine declension name in this module
-- 5. The value of hard= for the declensions_cat entry
-- 6. The value of decl= for the declensions_cat entry
-- 7. The value of possadj= for the declensions_cat entry (true if possessive
-- or similar type of adjective)
local adj_decl_map = {
{"ый", "ый", "ое", "ая", "hard", "long", false},
{"ій", "ій", "ее", "яя", "soft", "long", false},
{"ой", "ой", "о́е", "а́я", "hard", "long", false},
{"ьій", "ьій", "ье", "ья", "palatal", "long", true},
{"short", "ъ-short", "о-short", "а-short", "hard", "short", true},
{"mixed", "ъ-mixed", "о-mixed", "а-mixed", "hard", "mixed", true},
{"proper", "ъ-proper", "о-proper", "а-proper", "hard", "proper", true},
{"stressed-short", "ъ-stressed-short", "о-stressed-short", "а-stressed-short", "hard", "short", true},
{"stressed-proper", "ъ-stressed-proper", "о-stressed-proper", "а-stressed-proper", "hard", "proper", true},
}
local function get_adjectival_decl(adjtype, gender, old)
local decl, intnotes = m_ru_adj.get_nominal_decl(adjtype, gender, old)
-- hack fem ins_sg to insert <insa>, <insb>; see concat_word_forms_1()
if gender == "f" and type(decl["ins_sg"]) == "table" and #decl["ins_sg"] == 2 then
decl["ins_sg"][1] = decl["ins_sg"][1] .. "<insa>"
decl["ins_sg"][2] = decl["ins_sg"][2] .. "<insb>"
end
return decl, intnotes
end
for _, declspec in ipairs(adj_decl_map) do
local oadjdecl = declspec[1]
local nadjdecl = old_to_new(oadjdecl)
local odecl_by_gender =
{m="+" .. declspec[2], n="+" .. declspec[3], f="+" .. declspec[4]}
local hard = declspec[5]
local decltype = declspec[6]
local possadj = declspec[7]
for _, g in ipairs({"m", "n", "f"}) do
local odecl = odecl_by_gender[g]
local ndecl = old_to_new(odecl)
declensions_old[odecl], internal_notes_table_old[odecl] =
get_adjectival_decl(oadjdecl, g, true)
declensions[ndecl], internal_notes_table[ndecl] =
get_adjectival_decl(nadjdecl, g, false)
declensions_old_cat[odecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
declensions_cat[ndecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
end
end
-- Set up some aliases.
declensions_old_aliases["+о́-short"] = "+о-stressed-short"
declensions_old_aliases["+а́-short"] = "+а-stressed-short"
declensions_old_aliases["+о́-proper"] = "+о-stressed-proper"
declensions_old_aliases["+а́-proper"] = "+а-stressed-proper"
declensions_aliases["+#-short"] = "+-short"
declensions_aliases["+#-mixed"] = "+-mixed"
declensions_aliases["+#-proper"] = "+-proper"
declensions_aliases["+#-stressed-short"] = "+-stressed-short"
declensions_aliases["+#-stressed-proper"] = "+-stressed-proper"
--------------------------------------------------------------------------
-- Populate new from old --
--------------------------------------------------------------------------
-- Function to convert an entry in an old declensions table to new.
local function old_decl_entry_to_new(v)
if not v then
return nil
elseif type(v) == "table" then
local new_entry = {}
for _, i in ipairs(v) do
table.insert(new_entry, old_decl_entry_to_new(i))
end
return new_entry
elseif type(v) == "function" then
return function(stem, suffix, args)
return old_decl_entry_to_new(v(stem, suffix, args))
end
else
return old_to_new(v)
end
end
-- Function to convert an old declensions table to new.
local function old_decl_to_new(odecl)
local ndecl = {}
for k, v in pairs(odecl) do
ndecl[k] = old_decl_entry_to_new(v)
end
return ndecl
end
-- Function to convert an entry in an old declensions_cat table to new.
local function old_decl_cat_entry_to_new(odecl_cat_entry)
if not odecl_cat_entry then
return nil
elseif type(odecl_cat_entry) == "function" then
return function(suffix)
return old_decl_cat_entry_to_new(odecl_cat_entry(suffix))
end
elseif type(odecl_cat_entry) == "table" then
local ndecl_cat_entry = {}
for k, v in pairs(odecl_cat_entry) do
ndecl_cat_entry[k] = old_decl_cat_entry_to_new(v)
end
return ndecl_cat_entry
elseif type(odecl_cat_entry) == "boolean" then
return odecl_cat_entry
else
assert(type(odecl_cat_entry) == "string")
return old_to_new(odecl_cat_entry)
end
end
-- Function to convert an old declensions_cat table to new.
local function old_decl_cat_to_new(odeclcat)
local ndeclcat = {}
for k, v in pairs(odeclcat) do
ndeclcat[k] = old_decl_cat_entry_to_new(v)
end
return ndeclcat
end
-- populate declensions[] from declensions_old[]
for odecltype, odecl in pairs(declensions_old) do
local ndecltype = old_to_new(odecltype)
if not declensions[ndecltype] then
declensions[ndecltype] = old_decl_to_new(odecl)
end
end
-- populate declensions_cat[] from declensions_old_cat[]
for odecltype, odeclcat in pairs(declensions_old_cat) do
local ndecltype = old_to_new(odecltype)
if not declensions_cat[ndecltype] then
declensions_cat[ndecltype] = old_decl_cat_to_new(odeclcat)
end
end
-- populate declensions_aliases[] from declensions_old_aliases[]
for ofrom, oto in pairs(declensions_old_aliases) do
local from = old_to_new(ofrom)
if not declensions_aliases[from] then
declensions_aliases[from] = old_to_new(oto)
end
end
-- populate internal_notes_table[] from internal_notes_table_old[]
for odecl, note in pairs(internal_notes_table_old) do
local ndecl = old_to_new(odecl)
if not internal_notes_table[ndecl] then
-- FIXME, should we be calling old_to_new() here?
internal_notes_table[ndecl] = note
end
end
--------------------------------------------------------------------------
-- Inflection functions --
--------------------------------------------------------------------------
-- Attach the stressed stem (or plural stem, or barestem) out of ARGS
-- to the unstressed suffix SUF, modifying the suffix as necessary for the
-- last letter of the stem (e.g. if it is velar, sibilant or ц). CASE is
-- the case form being created and is used to select the plural stem if
-- needed. Returns two values, the combined form and the modified suffix.
local function attach_unstressed(args, case, suf, was_stressed)
if suf == nil then
return nil, nil
elseif rfind(suf, CFLEX) then -- if suf has circumflex accent, it forces stressed
return attach_stressed(args, case, suf)
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.pl, args.pltr
end
if not stem and case == "ins_sg" then
stem, tr = args.ins_sg_stem, args.ins_sg_tr
end
if not stem then
stem, tr = args.stem, args.stemtr
end
if nom.nonsyllabic_suffixes[suf] then
-- If gen_pl, use special args.gen_pl_bare if given, else regular
-- args.bare if there isn't a plural stem. If nom_sg, always use
-- regular args.bare.
local barearg, bareargtr
if case == "gen_pl" then
barearg, bareargtr = args.gen_pl_bare, args.gen_pl_baretr
if not barearg and args.pl == args.stem then
barearg, bareargtr = args.bare, args.baretr
end
else
barearg, bareargtr = args.bare, args.baretr
end
local barestem = barearg or stem
local barestem, baretr
if barearg then
barestem, baretr = barearg, bareargtr
else
barestem, baretr = stem, tr
end
if was_stressed and case == "gen_pl" then
if not barearg then
local gen_pl_stem, gen_pl_tr = com.make_ending_stressed(stem, tr)
barestem, baretr = gen_pl_stem, gen_pl_tr
end
end
if rlfind(barestem, "[йьъ]$") then
suf = ""
else
if suf == "ъ" then
-- OK
elseif suf == "й" or suf == "ь" then
if barearg and case == "gen_pl" then
-- explicit bare or reducible, don't add -ь
suf = ""
elseif rfind(barestem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
-- not reducible, do add -ь and correct to -й if necessary
suf = "й"
else
suf = "ь"
end
end
end
return com.concat_russian_tr(barestem, baretr, suf, nil, "dopair"), suf
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Analogous to attach_unstressed() but for the unstressed stem and a
-- stressed suffix.
attach_stressed = function(args, case, suf)
if suf == nil then
return nil, nil
end
-- circumflex forces stress even when the accent pattern calls for no stress
suf = rsub(suf, "̂", AC)
if com.is_unstressed(suf) then
return attach_unstressed(args, case, suf, "was stressed")
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.upl, args.upltr
end
if not stem then
stem, tr = args.ustem, args.ustemtr
end
local rules = nom.stressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Attach the appropriate stressed or unstressed stem (or plural stem as
-- determined by CASE, or barestem) out of ARGS to the suffix SUF, which may
-- be a list of alternative suffixes (e.g. in the inst sg of feminine nouns).
-- Calls FUN (either attach_stressed() or attach_unstressed()) to do the work
-- for an individual suffix. Returns two values, a list of combined forms
-- and a list of the real suffixes used (which may be modified from the
-- passed-in suffixes, e.g. by removing stress marks or modifying vowels in
-- various ways after a stem-final velar, sibilant or ц). Each combined form
-- is a two-element list {stem, tr} (or a one-element list if tr is nil).
-- IRREG is true if this is an irregular form. We are handling the Nth word;
-- ISLAST is true if this is the last one.
local function attach_with(args, case, suf, fun, irreg, n, islast)
if type(suf) == "table" then
local all_combineds = {}
local all_realsufs = {}
for _, x in ipairs(suf) do
local combineds, realsufs =
attach_with(args, case, x, fun, irreg, n, islast)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
for _, realsuf in ipairs(realsufs) do
table.insert(all_realsufs, realsuf)
end
end
return all_combineds, all_realsufs
else
local combined, realsuf = fun(args, case, suf)
local irregsuf = irreg and {IRREGMARKER} or {""}
return {combined and com.concat_paired_russian_tr(
com.concat_paired_russian_tr(args["prefix" .. n], combined),
com.concat_paired_russian_tr(args["suffix" .. n], irregsuf)) or nil},
{realsuf and realsuf .. args["suffix" .. n][1] or nil}
end
end
-- Generate the form(s) and suffix(es) for CASE according to the declension
-- table DECL, using the attachment function FUN (one of attach_stressed()
-- or attach_unstressed()). IS_SLASH is true if this is a slash declension
-- (different declensions for singular and plural). We are handling the Nth
-- word; ISLAST is true if this is the last one.
local function gen_form(args, decl, case, stress, fun, is_slash, n, islast)
local irreg = false
if not args.suffixes[case] then
args.suffixes[case] = {}
end
local decl_sufs = args.old and declensions_old or declensions
decl_sufs = decl_sufs[decl]
local suf = decl_sufs[case]
local decl_cats = args.old and declensions_old_cat or declensions_cat
local ispl = rfind(case, "_pl")
if ispl and (decl_cats[decl].irregpl or args.pl and args.pl ~= args.stem or is_slash) then
irreg = true
end
if case == "nom_pl" and decl_cats[decl].alt_nom_pl then
irreg = true
end
if type(suf) == "function" then
suf = suf(ispl and args.pl or args.stem, stress, args)
end
if case == "gen_pl" and args.alt_gen_pl then
suf = decl_sufs.alt_gen_pl
irreg = true
if not suf then
error("No alternative genitive plural available for this declension class")
end
end
local combineds, realsufs = attach_with(args, case, suf, fun, irreg, n, islast)
for _, realsuf in ipairs(realsufs) do
args.any_non_nil[case] = true
args.this_any_non_nil[case] = true
insert_if_not(args.suffixes[case], realsuf)
end
return combineds
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
}
do_stress_pattern = function(stress, args, decl, number, n, islast)
local f = {}
for _, case in ipairs(decl_cases) do
if not number or (number == "sg" and rfind(case, "_sg")) or
(number == "pl" and rfind(case, "_pl")) then
f[case] = gen_form(args, decl, case, stress,
attachers[stress_patterns[stress][case]], not not number,
n, islast)
-- Turn empty form lists into nil to facilitate computation of
-- animate/inanimate accusatives below
if f[case] and #f[case] == 0 then
f[case] = nil
end
-- Compute linked versions of potential lemma cases, for use
-- in the ru-noun+ headword. We substitute the original lemma
-- (before removing links) for forms that are the same as the
-- lemma, if the original lemma has links.
if f[case] and (case == "nom_sg" or case == "nom_pl") then
local linked_forms = {}
for _, form in ipairs(f[case]) do
-- Return true if FORM is "close enough" to LEMMA that we can substitute the
-- linked form of the lemma. Currently this means exactly the same except that
-- we ignore acute and grave accent differences in monosyllables, and ignore
-- notes that may have been appended (e.g. the triangle marking irregularity).
local entry, notes = m_table_tools.separate_notes(form[1])
local lemma = args.lemma_no_links
local close_enough_to_lemma =
entry == lemma or (com.is_monosyllabic(entry) and
com.is_monosyllabic(lemma) and
com.remove_accents(entry) == com.remove_accents(lemma))
if close_enough_to_lemma and
rfind(args.orig_lemma, "%[%[") then
table.insert(linked_forms, {args.orig_lemma .. notes, args.lemmatr and args.lemmatr .. notes})
else
table.insert(linked_forms, form)
end
end
f[case .. "_linked"] = linked_forms
end
end
end
-- Set acc an/in variants now as appropriate. We used to do this in
-- handle_forms_and_overrides(), which simplified the handling of
-- nom/gen/acc overrides but caused problems for words like мазло and
-- трепло that had a mixture of nil and non-nil accusative forms.
local an = args.thisa
if not number or number == "sg" then
f.acc_sg_an = f.acc_sg_an or f.acc_sg or an == "i" and f.nom_sg or f.gen_sg
f.acc_sg_in = f.acc_sg_in or f.acc_sg or an == "a" and f.gen_sg or f.nom_sg
end
if not number or number == "pl" then
f.acc_pl_an = f.acc_pl_an or f.acc_pl or an == "i" and f.nom_pl or f.gen_pl
f.acc_pl_in = f.acc_pl_in or f.acc_pl or an == "a" and f.gen_pl or f.nom_pl
end
for case, forms in pairs(f) do
if not args.forms[case] then
args.forms[case] = {}
end
for _, form in ipairs(forms) do
insert_if_not(args.forms[case], form)
end
end
end
stress_patterns["a"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["b"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["b'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["c"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["d"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["d'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["e"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f''"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
ending_stressed_gen_pl_patterns = m_table.listToSet({"b", "b'", "c", "e", "f", "f'", "f''"})
ending_stressed_pre_sg_patterns = m_table.listToSet({"b", "b'", "d", "d'", "f", "f'", "f''"})
ending_stressed_dat_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_pl_patterns = m_table.listToSet({"b", "b'", "c"})
local numbers = {
["s"] = "singular",
["p"] = "plural",
}
local old_title_temp = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local extra_case_template, extra_case_template_with_plural
local internal_notes_template
local notes_template
local templates = {}
-- Convert a raw override into a canonicalized list of individual overrides.
-- If input is nil, so is output. Certain junk (e.g. <br/>) is removed,
-- and ~ and ~~ are substituted appropriately; ARGS and CASE are required for
-- this purpose. FORMS is the list of existing case forms and is currently
-- used only to retrieve the dat_sg for handling + in loc/par (this means
-- that any overrides of the dat_sg have to be handled before handling
-- overrides of loc/par). N is the suffix used to retrieve the override --
-- either a number for word-specific overrides, or an empty string for
-- overall overrides.
--
-- It will still be necessary to call m_table_tools.separate_notes() to separate
-- off any trailing "notes" (asterisks, superscript numbers, etc.), and
-- m_links.remove_links() to remove any links to get the raw override form.
canonicalize_override = function(args, case, forms, n)
local val = args[case .. n]
if not val then
return nil
end
-- clean <br /> that's in many multi-form entries and messes up linking
val = rsub(val, "<br%s*/>", "")
-- substitute ~ and ~~ and split by commas
local stem, manualtr
if rfind(case, "_pl") then
stem, manualtr = args.pl, args.pltr
end
if not stem then
stem, manualtr = args.stem, args.stemtr
end
local ustem, umanualtr = com.make_unstressed_once(stem, manualtr)
local stemtr, ustemtr = manualtr, umanualtr
local vals = rsplit(val, "%s*,%s*")
local retvals = {}
for _, val in ipairs(vals) do
local valru, valtr = com.split_russian_tr(val)
valru = rsub(valru, "~~", ustem)
valru = rsub(valru, "~", com.is_stressed(val) and ustem or stem)
if rfind(valru, "^%*") then
valru = rsub(valru, "^%*", "") .. HYPMARKER
end
if valtr then
stemtr = stemtr or com.translit_no_links(stem)
ustemtr = ustemtr or com.translit_no_links(ustem)
valtr = rsub(valtr, "~~", ustemtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and ustemtr or stemtr)
elseif val:find("~") and manualtr then
valtr = com.translit_no_links(val)
valtr = rsub(valtr, "~~", umanualtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and umanualtr or manualtr)
end
if valtr then
if valtr:sub(1, 1) == "*" then
valtr = valtr:sub(2) .. HYPMARKER
end
valtr = com.j_correction(valtr)
end
table.insert(retvals, {valru, valtr})
end
vals = retvals
-- handle + in loc/par meaning "the expected form"; NOTE: This requires
-- that dat_sg has already been processed!
if case == "loc" or case == "par" then
local new_vals = {}
for _, rutr in ipairs(vals) do
-- don't just handle + by itself in case the arg has в or на
-- or whatever attached to it
if rfind(rutr[1], "^%+") or rfind(rutr[1], "[%s%[|]%+") then
for _, dat in ipairs(forms["dat_sg"]) do
local ru, tr = rutr[1], rutr[2]
local datru, dattr = dat[1], dat[2]
local valru, valtr
-- separate off any footnote symbols (which may have been
-- introduced by a *tail or *tailall argument, which we need
-- to process before this stage so overrides don't get
-- automatically marked with footnote symbols); if par,
-- try to preserve them, but with loc this can cause
-- problems in case there are multiple dative forms
-- (stress variants) and the last one is marked with a
-- footnote symbol (occurs in грудь)
local datru_entry, datru_notes = m_table_tools.separate_notes(datru)
local dattr_entry, dattr_notes
if dattr then
dattr_entry, dattr_notes = m_table_tools.separate_notes(dattr)
end
if case == "par" then
valru, valtr = datru_entry, dattr_entry
else
valru, valtr = com.make_ending_stressed(datru_entry, dattr_entry)
datru_notes = ""
dattr_notes = ""
end
-- wrap the word in brackets so it's linked; but not if it
-- appears to already be linked
ru = rsub(ru, "^%+", "[[" .. valru .. "]]")
ru = rsub(ru, "([%[|])%+", "%1" .. valru)
ru = rsub(ru, "(%s)%+", "%1[[" .. valru .. "]]")
ru = ru .. datru_notes
-- do the translit; but it shouldn't have brackets in it
if tr or valtr then
tr = tr or com.translit_no_links(rutr[1])
valtr = valtr or com.translit_no_links(valru)
tr = rsub(tr, "^%+", valtr)
tr = rsub(tr, "(%s)%+", "%1" .. valtr)
tr = tr .. dattr_notes
end
table.insert(new_vals, {ru, tr})
end
else
table.insert(new_vals, rutr)
end
end
vals = new_vals
end
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(vals) do
local ru, tr = v[1], v[2]
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. n .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
vals = newvals
return vals
end
local function process_overrides(args, f, n)
local function process_override(case)
if args[case .. n] then
local overrides = canonicalize_override(args, case, f, n)
if not f[case] then
f[case] = {}
end
local new_overrides = {}
for _, form in ipairs(overrides) do
-- Don't consider overrides of loc/par/voc irregular since
-- they're only specified through overrides; FIXME: Theoretically
-- we could consider loc/par irregular if they don't follow the
-- expected forms; but we'd have to figure out how to eliminate
-- the preposition that may be specified
if not overridable_only_cases_set[case] and
not args.manual and
not contains_rutr_pair(f[case], form) then
local formru, formnotes = m_table_tools.separate_notes(form[1])
if formru ~= "-" then
-- don't mark an override of - as irregular, even if
-- it has an attached footnote symbol
form = com.concat_paired_russian_tr(form, {IRREGMARKER})
end
end
if case == "pauc" then
-- Internal note indicating that the form is for numbers 2, 3 and 4.
form = com.concat_paired_russian_tr(form, {paucal_marker})
end
table.insert(new_overrides, form)
end
f[case] = new_overrides
args.any_overridden[case] = true
end
end
-- do dative singular first because it will be used by loc/par
process_override("dat_sg")
-- now do the rest
for _, case in ipairs(overridable_cases) do
if case ~= "dat_sg" then
process_override(case)
end
end
-- if the nominative is overridden, use it to set the linked version unless
-- that is also specifically overridden
if args["nom_sg" .. n] and not args["nom_sg_linked" .. n] then
f.nom_sg_linked = f.nom_sg
end
if args["nom_pl" .. n] and not args["nom_pl_linked" .. n] then
f.nom_pl_linked = f.nom_pl
end
-- convert empty lists to nil to facilitate computation of accusative
-- case variants below.
for _, case in ipairs(all_cases) do
if f[case] then
if type(f[case]) ~= "table" then
error("Logic error, args[case] should be nil or table")
end
if #f[case] == 0 then
f[case] = nil
end
end
end
end
local function process_tail_args(args, f, n)
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function handle_tail_hyp(suf)
local arg, val
for _, case in ipairs(all_cases) do
arg = args[case .. "_" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args[case .. "_" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
if not rfind(case, "_pl") then
arg = args["sg" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["sg" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
else
arg = args["pl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["pl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
if not rfind(case, "nom_") and not rfind(case, "acc_") then
arg = args["obl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["obl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
end
end
handle_tail_hyp("tail")
handle_tail_hyp("hyp")
end
handle_forms_and_overrides = function(args, n, islast)
local f = args.forms
process_tail_args(args, f, n)
process_overrides(args, f, n)
local an = args.thisa
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). This logic duplicates logic in handle_overall_forms_and_overrides();
-- see long comment there. We need to duplicate the whole logic here to
-- handle words like мать-одиночка, which has an override of acc_sg1.
if not args["acc_sg_an" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_an = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_an = f.acc_sg or an == "i" and f.nom_sg or f.gen_sg or f.acc_sg_an
end
end
if not args["acc_sg_in" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_in = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_in = f.acc_sg or an == "a" and f.gen_sg or f.nom_sg or f.acc_sg_in
end
end
if not args["acc_pl_an" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_an = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_an = f.acc_pl or an== "i" and f.nom_pl or f.gen_pl or f.acc_pl_an
end
end
if not args["acc_pl_in" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_in = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_in = f.acc_pl or an == "a" and f.gen_pl or f.nom_pl or f.acc_pl_in
end
end
f.loc = f.loc or f.pre_sg
f.par = f.par or f.gen_sg
f.voc = f.voc or f.nom_sg
-- Set these in case we have plural only, in which case the
-- singular will also get set to these same values in case we are
-- a plural-only word in a singular-only expression.
f.loc_pl = f.loc_pl or f.pre_pl
f.par_pl = f.par_pl or f.gen_pl
f.voc_pl = f.voc_pl or f.nom_pl
f.count = f.count or f.gen_pl
f.pauc = f.pauc or f.gen_sg
local nu = args.thisn
-- If we have a singular-only, set the plural forms to the singular forms,
-- and vice-versa. This is important so that things work in multi-word
-- expressions that combine different number restrictions (e.g.
-- singular-only with singular/plural or singular-only with plural-only,
-- compare "St. Vincent and the Grenadines" [Сент-Винсент и Гренадины]).
if nu == "s" then
f.nom_pl_linked = f.nom_sg_linked
f.nom_pl = f.nom_sg
f.gen_pl = f.gen_sg
f.dat_pl = f.dat_sg
f.acc_pl = f.acc_sg
f.acc_pl_an = f.acc_sg_an
f.acc_pl_in = f.acc_sg_in
f.ins_pl = f.ins_sg
f.pre_pl = f.pre_sg
f.nom_pl = f.nom_sg
f.loc_pl = f.loc
f.par_pl = f.par
f.voc_pl = f.voc
elseif nu == "p" then
f.nom_sg_linked = f.nom_pl_linked
f.nom_sg = f.nom_pl
f.gen_sg = f.gen_pl
f.dat_sg = f.dat_pl
f.acc_sg = f.acc_pl
f.acc_sg_an = f.acc_pl_an
f.acc_sg_in = f.acc_pl_in
f.ins_sg = f.ins_pl
f.pre_sg = f.pre_pl
f.nom_sg = f.nom_pl
f.loc = f.loc_pl
f.par = f.par_pl
f.voc = f.voc_pl
end
end
handle_overall_forms_and_overrides = function(args)
local overall_forms = {}
for _, case in ipairs(displayable_cases) do
overall_forms[case] = concat_word_forms(args.per_word_info, case)
end
local acc_sg_overridden = args.acc_sg
local acc_pl_overridden = args.acc_pl
process_tail_args(args, overall_forms, "")
process_overrides(args, overall_forms, "")
if case_will_be_displayed(args, "pauc") then
insert_if_not(args.internal_notes, paucal_internal_note)
end
-- if IRREGMARKER is anywhere in text, remove all instances and put
-- at the end before any notes.
local function clean_irreg_marker(case, text)
if rfind(text, IRREGMARKER) then
text = rsub(text, IRREGMARKER, "")
local entry, notes = m_table_tools.separate_notes(text)
if case_will_be_displayed(args, case) then
insert_if_not(args.internal_notes, IRREGMARKER .. " Irregular.")
args.any_irreg = true
args.any_irreg_case[case] = true
end
return entry .. IRREGMARKER .. notes
else
return text
end
end
-- set final args[case] and clean up IRREGMARKER.
for _, case in ipairs(all_cases) do
args[case] = overall_forms[case]
if args[case] then
local cleaned_forms = {}
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
ru = clean_irreg_marker(case, ru)
if tr then
tr = clean_irreg_marker(case, tr)
end
table.insert(cleaned_forms, {ru, tr})
end
args[case] = cleaned_forms
end
end
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). We need to do this somewhat complicated procedure to get overrides
-- to work correctly, e.g. acc_sg overrides of feminine and neuter nouns
-- (such as мать and полслова) and gen_sg/gen_pl overrides of masculine
-- animate nouns. We also ran into an issue with words like мазло that are
-- neuter-form but can be both masculine animate (in which case the
-- acc sg inherits from the genitive) and neuter animate (in which case the
-- acc sg has the fixed ending -о, same as nominative, despite the animacy).
-- Remember also that the animate/inanimate accusative variants are the ones
-- displayed, not the plain acc_sg/acc_pl ones.
if not args.any_overridden.acc_sg_an then
if acc_sg_overridden then
args.acc_sg_an = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_an = args.acc_sg or args.a == "i" and args.nom_sg or args.gen_sg or args.acc_sg_an
end
end
if not args.any_overridden.acc_sg_in then
if acc_sg_overridden then
args.acc_sg_in = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_in = args.acc_sg or args.a == "a" and args.gen_sg or args.nom_sg or args.acc_sg_in
end
end
if not args.any_overridden.acc_pl_an then
if acc_pl_overridden then
args.acc_pl_an = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_an = args.acc_pl or args.a == "i" and args.nom_pl or args.gen_pl or args.acc_pl_an
end
end
if not args.any_overridden.acc_pl_in then
if acc_pl_overridden then
args.acc_pl_in = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_in = args.acc_pl or args.a == "a" and args.gen_pl or args.nom_pl or args.acc_pl_in
end
end
-- Try to set the values of acc_sg and acc_pl. The only time we can't is
-- when the noun is bianimate and the anim/inan values are different.
-- This is used primarily for generate_forms() and generate_multi_forms(),
-- since we don't actually display these forms.
if args.a == "a" then
args.acc_sg = args.acc_sg or args.acc_sg_an
args.acc_pl = args.acc_pl or args.acc_pl_an
elseif args.a == "i" then
args.acc_sg = args.acc_sg or args.acc_sg_in
args.acc_pl = args.acc_pl or args.acc_pl_in
else -- bianimate
args.acc_sg = args.acc_sg or m_table.deepEquals(args.acc_sg_in, args.acc_sg_an) and args.acc_sg_in or nil
args.acc_pl = args.acc_pl or m_table.deepEquals(args.acc_pl_in, args.acc_pl_an) and args.acc_pl_in or nil
end
end
-- Subfunction of concat_word_forms(), used to implement recursively
-- generating all combinations of elements from WORD_FORMS (a list, one
-- element per word, of a list of the forms for a word, each of which is a
-- two-element list of {RUSSIAN, TR}) and TRAILING_FORMS (a list of forms, the
-- accumulated suffixes for trailing words so far in the recursion process,
-- again where each form is a two-element list {RUSSIAN, TR}). Each time we
-- recur we take the last FORMS item off of WORD_FORMS and to each form in
-- FORMS we add all elements in TRAILING_FORMS, passing the newly generated
-- list of items down the next recursion level with the shorter WORD_FORMS.
-- We end up returning a list of concatenated forms, where each list item
-- is a two-element list {RUSSIAN, TR}.
local function concat_word_forms_1(word_forms, trailing_forms)
if #word_forms == 0 then
local retforms = {}
for _, form in ipairs(trailing_forms) do
local ru, tr = form[1], form[2]
-- Remove <insa> and <insb> markers; they've served their purpose.
ru = rsub(ru, "<ins[ab]>", "")
tr = tr and rsub(tr, "<ins[ab]>", "")
table.insert(retforms, {ru, tr})
end
return retforms
else
local last_form_info = table.remove(word_forms)
local last_forms, joiner = last_form_info[1], last_form_info[2]
local new_trailing_forms = {}
for _, form in ipairs(last_forms) do
for _, trailing_form in ipairs(trailing_forms) do
-- If form to prepend is empty, don't add the joiner; this
-- is principally used in overall overrides, where we stuff
-- the entire override into the last word
local full_form = form[1] == "" and trailing_form or
com.concat_paired_russian_tr(form,
com.concat_paired_russian_tr(joiner, trailing_form),
"movenotes")
if rfind(full_form[1], "<insa>") and rfind(full_form[1], "<insb>") then
-- REJECT! So we don't get mixtures of the two feminine
-- instrumental singular endings.
else
table.insert(new_trailing_forms, full_form)
end
end
end
return concat_word_forms_1(word_forms, new_trailing_forms)
end
end
-- Generate a list of overall forms by concatenating the per-word forms.
-- PER_WORD_INFO comes from args.per_word_info and is a list of
-- WORD_INFO items, one per word, each of which a two element list of
-- WORD_FORMS (a table listing the forms for each case) and JOINER (a string).
-- We loop over all possible combinations of elements from each word's list
-- of forms for the given case; this requires recursion.
concat_word_forms = function(per_word_info, case)
local word_forms = {}
-- Gather the appropriate word forms. We have to recreate this anew
-- because it will be destructively modified by concat_word_forms_1().
for _, word_info in ipairs(per_word_info) do
table.insert(word_forms, {word_info[1][case], word_info[2]})
end
-- We need to start the recursion with the second parameter containing
-- one blank element rather than no elements, otherwise no elements
-- will be propagated to the next recursion level.
return concat_word_forms_1(word_forms, {{""}})
end
local accel_forms = {
nom_sg = "nom|s",
nom_sg_linked = "nom|s",
nom_pl = "nom|p",
nom_pl_linked = "nom|p",
gen_sg = "gen|s",
gen_pl = "gen|p",
dat_sg = "dat|s",
dat_pl = "dat|p",
acc_sg_an = "an|acc|s",
acc_pl_an = "an|acc|p",
acc_sg_in = "in|acc|s",
acc_pl_in = "in|acc|p",
ins_sg = "ins|s",
ins_pl = "ins|p",
pre_sg = "pre|s",
pre_pl = "pre|p",
loc = "loc|s",
loc_pl = "loc|p",
voc = "voc|s",
voc_pl = "voc|p",
par = "par|s",
par_pl = "par|p",
count = "count form",
pauc = "pau",
}
-- Make the table
make_table = function(args)
local data = {}
data.after_title = " " .. args.heading
data.number = args.nonumber and "" or numbers[args.n]
local lemma_forms = args[args.n == "p" and "nom_pl" or "nom_sg"]
data.lemma = nom.show_form(args.explicit_lemma and {{args.explicit_lemma, args.explicit_lemmatr}} or
args[args.n == "p" and "nom_pl_linked" or "nom_sg_linked"], "lemma", nil, nil)
data.title = args.title or format(args.old and old_title_temp or title_temp, data)
local sg_an_in_equal = m_table.deepEquals(args.acc_sg_an, args.acc_sg_in)
local pl_an_in_equal = m_table.deepEquals(args.acc_pl_an, args.acc_pl_in)
for _, case in ipairs(displayable_cases) do
local accel_form = accel_forms[case]
if not accel_form then
error("Something wrong, can't find accelerator form for " .. case)
end
if (sg_an_in_equal and (case == "acc_sg_an" or case == "acc_sg_in") or
pl_an_in_equal and (case == "acc_pl_an" or case == "acc_pl_in")) then
accel_form = rsub(accel_form, "^[ai]n|", "")
end
if args.n == "p" then
accel_form = rsub(accel_form, "|p$", "")
end
data[case] = nom.show_form(args[case], false, accel_form, lemma_forms, "remove monosyllabic accents only lemma")
end
local temp = nil
if args.n == "s" then
data.nom_x = data.nom_sg
data.gen_x = data.gen_sg
data.dat_x = data.dat_sg
data.acc_x_an = data.acc_sg_an
data.acc_x_in = data.acc_sg_in
data.ins_x = data.ins_sg
data.pre_x = data.pre_sg
if sg_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
elseif args.n == "p" then
data.nom_x = data.nom_pl
data.gen_x = data.gen_pl
data.dat_x = data.dat_pl
data.acc_x_an = data.acc_pl_an
data.acc_x_in = data.acc_pl_in
data.ins_x = data.ins_pl
data.pre_x = data.pre_pl
data.par = data.par_pl
data.loc = data.loc_pl
data.voc = data.voc_pl
if pl_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
else
if pl_an_in_equal then
temp = "both_numbers"
elseif sg_an_in_equal then
temp = "both_numbers_split_animacy_plural_only"
else
temp = "both_numbers_split_animacy"
end
end
for _, extra_case in ipairs({
{"par", "partitive"},
{"loc", "locative"},
{"voc", "vocative"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "s" and args.n ~= "p" and args.any_overridden[case .. "_pl"] then
if not args.any_overridden[case] then
data[case] = ""
end
template = extra_case_template_with_plural
elseif args.n ~= "p" and args.any_overridden[case] or args.n == "p" and args.any_overridden[case .. "_pl"] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
for _, extra_case in ipairs({
{"count", "count form"},
{"pauc", "paucal"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "p" and args.any_overridden[case] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
local notes = get_arg_chain(args, "notes", "notes")
local all_notes = {}
for _, note in ipairs(args.internal_notes) do
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
for _, note in ipairs(notes) do
-- Here too.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
data.notes = table.concat(all_notes, "<br />")
data.notes_clause = data.notes ~= "" and format(notes_template, data) or ""
return format(templates[temp], data)
end
function extra_case_template(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
|
|-]===]):format(colspan)
end
function extra_case_template_with_plural(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
| {\op}{case}_pl{\cl}
|-]===]):format(colspan)
end
notes_template = [===[
<div style="width:100%;text-align:left;background:var(--wikt-palette-lightblue, #d9ebff);">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame" data-toggle-category="လဟုတ်စှ်ေ" style="max-width:MINWIDTHem">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);">{title}<span style="font-weight:normal;">{after_title}</span> </div>
<div class="NavContent">
{\op}| style="table-layout:fixed; text-align:center; max-width:MINWIDTHem; width:100%;" class="inflection inflection-table"
|- class="rowgroup"
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[|-{par_clause}{loc_clause}{voc_clause}{count_clause}{pauc_clause}
|{\cl}{notes_clause}</div></div></div>]===]
end
templates["both_numbers"] = template_prelude("45") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_sg_in}
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy_plural_only"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 rowspan=2 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["one_number"] = template_prelude("30") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
templates["one_number_split_animacy"] = template_prelude("35") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| {acc_x_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
return export
kloi717bco8ip8kl4qawq685vie2std
399799
399798
2026-07-21T03:01:42Z
Intobesa.bot
1035
Bot: ပွမကၠာဲစုတ်ယၟုနူဘာသာအၚ်္ဂလိက်
399799
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
nouns.
Author: Benwing, rewritten from early version by Wikitiki89
Form of arguments: One of the following:
1. LEMMA|DECL|PLSTEM (all arguments optional)
2. ACCENT|LEMMA|DECL|PLSTEM (all arguments optional)
3. multiple sets of arguments separated by the literal word "or"
Arguments:
ACCENT: Accent pattern (a b c d e f b' d' f' f''). Multiple values can
be specified, separated by commas. If omitted, defaults to a or b
depending on the position of stress on the lemma or
explicitly-specified declension.
LEMMA: Lemma form (i.e. nom sg or nom pl), with appropriately-placed
stress; or the stem, if an explicit declension is specified
(in this case, the declension usually looks like an ending, and
the stem is the portion of the lemma minus the ending). In the
first argument set (i.e. first set of arguments separated
by "or"), defaults to page name; in later sets, defaults to lemma
of previous set. A plural form can be given, and causes argument
n= to default to n=p (plural only). Normally, an accent is
required if multisyllabic, and unaccented monosyllables with
automatically be stressed; prefix with * to override both behaviors.
DECL: Declension field. Normally omitted to autodetect based on the
lemma form; see below.
PLSTEM: special plural stem (defaults to stem of lemma)
Additional named arguments:
a: animacy (a/an/anim = animate, i/in/inan = inanimate, b/bi/both/ai = both
(listing animate first in the headword), ia = both (listing inanimate
first in the headword), otherwise inanimate)
n: number restriction (p = plural only, s = singular only, b = both;
defaults to both unless the lemma is plural, in which case it
defaults to plural only)
CASE_NUM or acc_NUM_ANIM or par/loc/voc: override (or multiple
values separated by commas) for case/number combination;
forms auto-linked; can have raw links in it, can have an
ending "note" (*, +, 1, 2, 3, etc.)
pltail: Specify something (usually a * or similar) to attach to
the end of the last plural form when there's more than one. Used in
conjunction with notes= to indicate that alternative plural forms
are obsolete, poetic, etc.
pltailall: Similar pltail= but attaches to all plural forms.
Typically used in conjunction with notes= to make a comment about
the plural as a whole (e.g. it's mostly hypothetical, rare and
awkward, etc.).
sgtail, sgtailall: Same as pltail=, pltailall= but for the singular.
obltail, obltailall: Same as pltail=, pltailall= but for oblique cases
(not the nominative or accusative).
CASE_NUM_tail: Attach the argument to the end of the last form
(whether there's one or more than one) for the particular
case/number combination. Note that this doesn't work quite like
pltail= or sgtail= in that it doesn't skip adding the argument
when there's only one form.
CASE_NUM_tailall: Attach the argument to the end of all forms
specified for the particular case/number combination. Similar to
pltailall= or sgtailall=.
suffix: Add a suffix such as ся to all forms.
prefix: Add a prefix to all forms.
plhyp, plhypall, CASE_NUM_hyp, etc.: Same as pltail, pltailall,
CASE_NUM_tal, etc. but specify that the marked forms are
mostly hypothetical or rare/awkard. Generally you will want
plhypall=y to mark the plural as hypothetical.
Per word named arguments:
All of the above named arguments have per-word variants, e.g.
a1, a2, ...; n1, n2, ...; CASE_NUM1, CASE_NUM2, ...;
pltail1, pltail2, ...; etc. These apply to the individual words of a
form.
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
par: partitive
loc: locative
voc: vocative
Number abbreviations:
sg: singular
pl: plural
Animacy abbreviations:
an: animate
in: inanimate
Declension field:
One of the following for regular nouns:
(blank)
GENDER
-VARIANT
GENDER-VARIANT
$
DECLTYPE
DECLTYPE/DECLTYPE
(also, can append various special-case markers to any of the above)
Or one of the following for adjectival nouns:
+
+ь
$
+short, +mixed or +proper
+DECLTYPE
GENDER if present is m, f, n or 3f; for regular nouns, required if the
lemma ends in -ь or is plural, ignored otherwise. 3f is the same
as f but in the case of a plural lemma in -и, detects a
third-declension feminine with singular in -ь rather than a
first-declension feminine with singular in -а or -я.
VARIANT is one way of requesting variant declensions (see also special
case (1) for variant nom pls, and special case (2) for variant
gen pls). The currently allowed values are -ья (will select a
mixed declension that has some normal declension in its singular
and the -ья plural declension); -ин (for animate masculine nouns
in -ин with plural in -е -- note that this is autodetected in the
majority of cases where the ending in -янин or -анин); -ишко
(used for inanimate neuter-form diminutive masculine nouns in
-ишко [also сараю́шко] with nom pl -и and colloquial feminine-ending
alternants in some singular cases); -ище (similar to -ишко but
used for *animate* augmentative masculine neuter-form nouns in
-ище). Variants -ишко and -ище must be given with with special
case (1).
$ is indeclinable words. It is principally useful in multiword
expressions where some of the words are indeclinable.
DECLTYPE is an explicit declension type. Normally you shouldn't use
this, and should instead let the declension type be autodetected
based on the ending, supplying the appropriate hint if needed
(gender for regular nouns, +ь for adjectives). If provided, the
declension type is usually the same as the ending, and if present,
the lemma field should be just the stem, without the ending.
Possibilities for regular nouns are (blank) or # for hard-consonant
declension, а, я, о, е or ё, е́, й, ья, ье or ьё, ь-m, ь-f,
ин, ёнок or онок or енок, ёночек or оночек or еночек, мя,
-а or #-а, ь-я, й-я, о-и or о-ы, -ья or #-ья, $ (indeclinable).
Old-style (pre-reform) declensions use ъ instead of (blank), ъ-а
instead of -а, ъ-ья instead of -ья, and инъ, ёнокъ/онокъ/енокъ,
ёночекъ/оночекъ/еночекъ instead of the same without terminating ъ.
The declensions can also be written with an accent on them; this
chooses the same declension (except for е vs. е́), but causes
ACCENT to default to pattern b instead of a.
For adjectival nouns, you should normally supply just + and let
the ending determine the declension; supply +ь in the case of a
possessive adjectival noun in -ий, which have an extra -ь- in
most endings compared with normal adjectival nouns in -ий, but
which can't be distinguished based on the nominative singular.
You can also supply +short, +mixed or +proper, which constrains
the declension appropriately but still autodetects the
gender-specific and stress-specific variant. If you do supply
a specific declension type, as with regular nouns you need to
omit the ending from the lemma field and supply just the stem.
Possibilities are +ый, +ое, +ая, +ій, +ее, +яя, +ой, +о́е, +а́я,
+ьій, +ье, +ья, +-short or +#-short (masc), +о-short,
+о-stressed-short or +о́-short, +а-short, +а-stressed-short or
+а́-short, and similar for -mixed and -proper (except there aren't
any stressed mixed declensions).
DECLTYPE/DECLTYPE is used for nouns with one declension in the
singular and a different one in the plural, for cases that
PLVARIANT and special case (1) below don't cover.
Special-case markers:
(1) for Zaliznyak-style alternative nominative plural ending:
-а or -я for masculine, -и or -ы for neuter
(2) for Zaliznyak-style alternative genitive plural ending:
-ъ/none for masculine, -ей for feminine, -ов(ъ) for neuter,
-ей for plural variant -ья
* for reducibles (nom sg or gen pl has an extra vowel before the
final consonant as compared with the stem found in other cases)
;ё for Zaliznyak-style alternation between last е in stem and ё
TODO:
1. Multi-word issues:
-- FIXME: Make sure internal_notes handled correctly; we may run into issues
with multiple internal notes from different words, if we're not careful
to use different footnote symbols for each type of footnote (which we
don't do currently). [NOT DONE, MAY NOT DO]
-- Handling default lemma: With multiple words, we should probably split
the page name on spaces and default each word in turn [NOT DONE, MAY
NOT DO]
2a. FIXME: For -ишко diminutives and -ище augmentatives, should add an
appropriate category of some sort (currently marked by colloqfem= in
category).
2b. FIXME: Adding a note to dat_sg also adds it to loc_sg when it exists;
seems wrong. See луг.
2c. FIXME: When you have both d' and f in feminines and you use sgtail=*,
you get two *'s. See User:Benwing2/test-ru-noun-debug.
3. ADJECTIVE FIXMES:
3a. FIXME: Change calls to ru-adj11 to use the new proper name support in
ru-adjective.
3b. FIXME: Test that omitting a manual form in ru-adjective leaves the form as
a big dash.
3c. FIXME: какой-либо and какой-то display genitives with translit -go
instead of -vo. To fix this properly requires implementing real
manual translit for adjectives.
3d. FIXME: Implement real manual translit for adjectives.
5. [FIXME: Consider adding an indicator in the header line when the ё/e
alternation occurs. This is a bit tricky to calculate: If special case
;ё is given, but also if ё occurs in the stem and the accent pattern is
as follows -- for sg-only, b' d' f' f'', also b d f if the noun is masc
or 3rd-decl fem (i.e. nom-sg ending is non-syllabic); for pl-only,
e f f' f'', also b b' c if the gen pl is non-syllabic; for sg/pl,
any but a or b, also b if either nom sg or gen pl is non-syllabic. But
it gets more complicated due to overrides. An alternative is to check
all forms to see if ё is present in some but not all; but this is
tricky also because e.g. reducibles frequently have ё/null alternation,
which doesn't count, and some endings have е or ё in them, which also
doesn't count. If we were to do it this way, we'd have to (a) count
the number of е's in the form(s) with ё and verify that there's at least
one form without ё and with one more е than in the form(s) with ё
(and it gets trickier if different forms with ё have different numbers of
е in them, although that is probably rare); and (b) ignore the appropriate
endings (the best way to do this would probably be to look at the actual
suffixes that were generated in args.suffixes and chop off any matching
ending in the actual form(s), but also chop off final -е/ё, as well as
-ев(ъ)/-ёв(ъ)/-ей/-ёй in the gen pl, which is frequently overridden,
unless perhaps the stem ends in the same way). It'd probably not
possible to do this in a 100% foolproof way but can be "good enough" for
nearly all circumstances.] [MIGHT BE TOO MUCH WORK]
6. HEADWORD FIXMES:
6a. FIXME: In ru-headword, create a category for words whose gender doesn't
match the form. (This is easy to do for ru-noun+ but harder for ru-noun.
We would need to do limited autodetection of the ending: for singulars,
-а/я should be feminine, -е/о/ё should be neuter, -ь should be masculine
or feminine, anything else should be masculine; for plurals, -и/ы should
be masculine or feminine, -а/я should be neuter except that -ія can be
feminine or neuter due to old-style adjectival pluralia tantum nouns,
anything else can be any gender.)
6b. FIXME: Recognize indeclinable nouns and indicate as indeclinable. Probably
should work by checking the case forms to see if they're the same.
9. FIXME: Change stress-pattern detection and overriding to happen inside of
looping over the two parts of a slash decl. Requires that the loop over
the two parts happen outside of the loop over stress patterns. Requires
that the category code get split into two parts, one to handle combined
singular/plural categories that goes outside the two loops, and one to
handle everything else that goes inside the two loops.
10. FIXME: override_matches_suffix() had a free variable reference to ARGS
in it, which should have triggered an error whenever there was a nom_sg or
nom_pl override but didn't. Is there an error causing this never to be
called? Check.
11a. FIXME: In a multiword lemma, using loc2=+ causes only the second word
to get linked instead of the whole expression. Same for par2=+, voc2=+.
11b. FIXME: Using loc=+ with a multiword lemma should do the right thing, same
as if locN=+ is specified for each individual word. Instead it generates
the locative as a whole from the dative, which fails e.g. if some of the
words are adjectival. Same for par=+, voc=+.
13. Multi-word issues:
-- Setting n=pl when auto-detecting a plural lemma. How does that interact
with multi-word stuff? (DONE)
-- compute_heading() -- what to do with multiple words? I assume we should
display info on the first noun (non-indeclinable, non-adjectival), and
on the first adjectival word otherwise, and finally on an indeclinable word (DONE)
-- args.genders -- it should presumably come from the same word as is used
in compute_heading(); but we should allow the overall gender to be
overridden, at least in ru-noun+ (DONE)
-- Bug in args.suffix: Gets added to every word in attach_with() and then
again at the end, after pltail and such. Needs to be added to the
last word only, before pltail. Need also suffixN for individual words.
(DONE, NEEDS TESTING)
-- Should have ..N versions of pltail and variants. (DONE, NEEDS TESTING)
-- Need to handle overrides of acc_sg, acc_pl (DONE)
-- Overrides of nom_sg/nom_pl should also override acc_sg/acc_pl if it
was originally empty and the animacy is inanimate; similarly for
gen_sg/gen_pl and animates; this needs to work both for per-word and
overall overrides. (DONE)
-- do_generate_forms(_multi) need to run part of make_table(), enough to
combine all per_word_info into single lists of forms and store back
into args[case]. (DONE, NEEDS TESTING)
-- In generate_forms, should probably check if a=="i" and only return
acc_sg_in as acc_sg=; or if a=="a" and only return acc_sg_an as acc_sg=;
in old/new comparison code, do something similar, also when a=="b"
check if acc_sg_in==acc_sg_an and make it acc_sg; when a=="b" and the
_in and _an variants are different, might need to ignore them or check
that acc_sg_in==nom_sg and acc_sg_an==gen_sg; similarly for _pl
(DONE, NEEDS TESTING)
-- Need to test with multiple words! [DONE]
-- Current handling of <adj> won't work properly with multiple words;
will need to translate word-by-word in that case (should be solved by
manual-translit branch) [DONE]
14. In multiple-words branch, fix ru-decl-noun-multi so it recognizes
things like *, (1), (2) and ; without the need for a separator. Consider
using semicolon as a separator, since we already use it to separate ё
from a previous declension. Maybe use $ or ~ for an indeclinable word; don't
use semicolon. [IMPLEMENTED. NEED TO TEST.]
16. [Consider having ru-noun+ treat par= as a second genitive in
the headword, as is done with край] [WON'T DO]
17. [FIXME: Consider removing slash patterns and instead handling them by
allowing additional declension flags 'sg' and 'pl'. This simplifies the
various special cases caused by slash declensions. It would also be
possible to remove the special plural stem, which would get rid of more
special cases. On the other hand, it makes it more complicated to support
plural variant -ья with all singular types, and the category code that
displays things like "Russian nouns with singular -X and plural -Y"
also gets more complicated, and there's something convenient and intuitive
about plural stems, and slash declensions are also convenient and at least
somewhat intuitive. One possibility is to externally allow slash
declensions and special plural stems and rewrite them internally to
separate stems with 'sg' and 'pl' declension flags; but there are still
the two coding issues mentioned above.]
18. [FIXME: Consider redoing slash patterns so they operate at the outer
level, i.e. things like special cases apply separately in the singular
and plural part of the slash pattern.]
19. In ru-noun, don't recognize -а with m as plural unless (1)
or n=pl is also given, because there are masculine words with the
feminine ending. Check using the test code whether this changes
anything. Also check if there are other similar cases (neuter with
-и isn't parallel because -и is always plural). [IMPLEMENTED. NEED TO TEST.]
19a. Internal notes weren't propagated properly from adjectives.
[IMPLEMENTED. NEED TO TEST.]
19b. Add support for -ишко and -ище variants (p. 74 of Z),
which conversationally and/or colloquially have feminine endings in
certain cases. [IMPLEMENTED. NEED TO TEST. MAKE SURE THE INTERNAL NOTES
APPEAR.]
19d. For masculine animate neuter-form nouns, the accusative singular
ends in -а (-я soft) instead of -о. [IMPLEMENTED. NEED TO TEST.
NOTE: Currently this variant only can be selected using new-style
arguments where the gender can be given. Perhaps we should consider
allowing gender to be specified with old-style explicit declensions.]
21. Put back gender hints for pl adjectival nouns; used by ru-noun+.
[IMPLEMENTED. NEED TO TEST.]
23. Mixed and proper-noun adjectives have built-in notes. We need to
handle those notes with an "internal_notes" section similar to what is used
in the adjective module. [IMPLEMENTED. NEED TO TEST.]
24. Adjective detection code here needs to work the same as for the
adjective module, in particular in the handling of short, stressed-short,
mixed, proper, stressed-proper. [IMPLEMENTED. NEED TO TEST.]
25. Consider simplifying plural-variant code to only allow -ья as a
plural variant [and maybe even change that to be something like (1')].
[IMPLEMENTED REDUCTION OF PLURAL VARIANTS TO -ья; PLURAL-VARIANT CODE
STILL COMPLEX, THOUGH. NEED TO TEST.]
26. Automatically superscript *, numbers and similar things at the
beginning of a note. Also do this in adjective module. [IMPLEMENTED.
NEED TO TEST.]
28. Make the check for multiple stress patterns (categorizing/tracking)
smarter, to keep a list of them and check at the end, so we handle
multiple stress patterns specified through different arg sets.
[IMPLEMENTED; NEED TO TEST.]
29. More sophisticated handling of user-requested plural variant vs. special
case (1) vs. plural-detected variant. [IMPLEMENTED. NEED TO TEST FURTHER.]
30. Solution to ambiguous plural involving gender spec "3f". [IMPLEMENTED;
NEED TO TEST. Use запчасти, новости.]
33. With pluralia tantum adjectival nouns, we don't know the gender.
By default we assume masculine (or feminine for old-style -ія nouns) and
currently this goes into the category, but shouldn't. [IMPLEMENTED.]
39. [Eventually: Even with decl type explicitly given, the full stem with
ending should be included.] [MAY NEVER IMPLEMENT]
40. [Get error "Unable to dereduce" with strange noun ва́йя, what should
happen?] [WILL NOT FIX; USE AN OVERRIDE]
41. In творог, module generates partitive творогу́ when it should copy the
dative творогу́,тво́рогу. (DONE)
42. [[груз 200]] doesn't work. Interprets 200 as a footnote symbol.
43. When converting е -> ё not after cons and with translit, we should
convert e -> o to avoid double j. (DONE)
44. FIXME: In ро́вня/ровня́, similarly with неровня, marks genitive plural
ровня́ as irregular even though it isn't. (NOT OUR ERROR; THE DECLENSIONS
OF THESE NOUNS MARKED THE ENDING-STRESSED VARIANTS WITH (2).)
]=]--
local m_utilities = require("Module:utilities")
local m_table = require("Module:table")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local m_ru_adj = require("Module:ru-adjective")
local m_str_utils = require("Module:string utilities")
local scriptutils = require("Module:script utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
local Latn = require("Module:scripts").getByCode("Latn")
local format = m_str_utils.format
local rfind = m_str_utils.find
local rsubn = m_str_utils.gsub
local rmatch = m_str_utils.match
local rsplit = m_str_utils.split
local u = m_str_utils.char
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same. Eventually consider removing this;
-- but useful as new code is created.
local test_new_ru_noun_module = false
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local DIA = u(0x0308) -- diaeresis = ̈
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder, matching ru-common
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
local paucal_marker = "*"
local paucal_internal_note = "* Used with the numbers 1.5, 2, 3, 4 and higher numbers after 20 ending in 2, 3, and 4."
-- text class to check lowercase arg against to see if Latin text embedded in it
local latin_text_class = "[a-zščžěáéíóúýàèìòùỳâêîôûŷạẹịọụỵȧėȯẏ]"
-- Forward functions
local generate_forms_1
local determine_decl
local handle_forms_and_overrides
local handle_overall_forms_and_overrides
local concat_word_forms
local make_table
local detect_adj_type
local detect_stress_pattern
local override_stress_pattern
local determine_stress_variant
local determine_stem_variant
local is_reducible
local is_dereducible
local add_bare_suffix
local attach_stressed
local do_stress_pattern
local canonicalize_override
-- 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
-- version of rfind() that lowercases its string first, for case-insensitive matching
local function rlfind(term, foo)
return rfind(ulower(term), foo)
end
local function track(page)
m_debug.track("ru-noun/" .. page)
return true
end
-- version of m_table.insertIfNot() that makes sure 'false' doesn't get inserted by mistake.
local function insert_if_not(foo, bar)
assert(bar ~= false)
m_table.insertIfNot(foo, bar)
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-- FIXME: Move to utils
-- Iterate over a chain of parameters, FIRST then PREF2, PREF3, ...,
-- inserting into LIST (newly created if omitted). Return LIST.
local function get_arg_chain(args, first, pref, list)
if not list then
list = {}
end
local val = args[first]
local i = 2
while val do
table.insert(list, val)
val = args[pref .. i]
i = i + 1
end
return list
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
local function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
local function rutr_pairs_equal(term1, term2)
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
local ru1entry, ru1notes = m_table_tools.separate_notes(m_links.remove_links(ru1))
local ru2entry, ru2notes = m_table_tools.separate_notes(m_links.remove_links(ru2))
if ru1entry ~= ru2entry then
return false
end
local tr1entry, tr1notes
local tr2entry, tr2notes
if tr1 then
tr1entry, tr1notes = m_table_tools.separate_notes(tr1)
end
if tr2 then
tr2entry, tr2notes = m_table_tools.separate_notes(tr2)
end
if tr1entry == tr2entry then
return true
elseif type(tr1entry) == type(tr2entry) then
return false
else
tr1entry = tr1entry or com.translit_no_links(ru1entry)
tr2entry = tr2entry or com.translit_no_links(ru2entry)
return tr1entry == tr2entry
end
end
local function contains_rutr_pair(list, pair)
for _, item in ipairs(list) do
if rutr_pairs_equal(item, pair) then
return true
end
end
return false
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
args[pname] = ine(param)
end
return args
end
-- Old-style declensions.
local declensions_old = {}
-- New-style declensions; computed automatically from the old-style ones,
-- for the most part.
local declensions = {}
-- Internal notes for old-style declensions.
local internal_notes_table_old = {}
-- Same for new-style declensions.
local internal_notes_table = {}
-- Category and type information corresponding to declensions: These may
-- contain the following fields: 'singular', 'plural', 'decl', 'hard', 'g',
-- 'suffix', 'gensg', 'irregpl', 'alt_nom_pl', 'cant_reduce', 'ignore_reduce',
-- 'stem_suffix'.
--
-- 'singular' is used to construct a category of the form
-- "Russian nouns SINGULAR". If omitted, a category is constructed of the
-- form "Russian nouns ending in -ENDING", where ENDING is the actual
-- nom sg ending shorn of its acute accents; or "Russian nouns ending
-- in suffix -ENDING", if 'suffix' is true. The value of SINGULAR can be
-- one of the following: a single string, a list of strings, or a function,
-- which is passed one argument (the value of ENDING that would be used to
-- auto-initialize the category), and should return a single string or list
-- of strings. Such a category is only constructed if 'gensg' is true.
--
-- 'plural' is analogous but used to construct a category of the form
-- "Russian nouns with PLURAL", and if omitted, a category is constructed
-- of the form "Russian nouns with plural -ENDING", based on the actual
-- nom pl ending shorn of its acute accents. Currently no plural category
-- is actually constructed.
--
-- In addition, a category may normally constructed from the combination of
-- 'singular' and 'plural', appropriately defaulted; e.g. if both are present,
-- the combined category will be "Russian nouns SINGULAR with PLURAL" and
-- if both are missing, the combined category will be
-- "Russian nouns ending in -SGENDING with plural -PLENDING" (or
-- "Russian nouns ending in suffix -SGENDING with plural -PLENDING" if
-- 'suffix' is true). Note that if either singular or plural or both
-- specifies a list, looping will occur over all combinations. Such a
-- category is constructed only if 'irregpl' or 'alt_nom_pl' or 'suffix'
-- is true or if the declension class is a slash class.
--
-- 'decl' is "1st", "2nd", "3rd" or "indeclinable"; 'hard' is "hard", "soft"
-- or "none"; 'g' is "m", "f", "n" or "none"; these are all traditional
-- declension categories.
--
-- If 'suffix' is true, the declension type includes a long suffix
-- added to the string that itself undergoes reducibility and such, and so
-- reducibility cannot occur in the stem minus the suffix. Categories will
-- be created for the suffix.
--
-- 'alt_nom_pl' indicates that the declension has an alternative nominative
-- plural (corresponding to Zaliznyak's special case 1; compare special case 2
-- for alternative genitive plural). 'irregpl' indicates that the entire
-- plural is irregular.
--
-- In addition to the above categories, additional more specific categories
-- are constructed based on the final letter of the stem, e.g.
-- "Russian velar-stem 1st-declension hard nouns". See calls to
-- com.get_stem_trailing_letter_type(). 'stem_suffix', if present, is added to
-- the end of the stem when get_stem_trailing_letter_type() is called.
-- This is the only place that 'stem_suffix' is used. This is for use with
-- the '-ья' and '-ье' declension types, so that the trailing letter is
-- 'ь' and not whatever precedes it.
--
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
-- Category/type info corresponding to old-style declensions; see above.
local declensions_old_cat = {}
-- Category/type info corresponding to new-style declensions. Computed
-- automatically from the old-style ones, for the most part. Same format
-- as the old-style ones.
local declensions_cat = {}
-- Table listing aliases of old-style declension classes.
local declensions_old_aliases = {}
-- Table listing aliases of new-style declension classes; computed
-- automatically from the old-style ones.
local declensions_aliases = {}
local stress_patterns = {}
-- Set of patterns with ending-stressed genitive plural.
local ending_stressed_gen_pl_patterns = {}
-- Set of patterns with ending-stressed prepositional singular.
local ending_stressed_pre_sg_patterns = {}
-- Set of patterns with ending-stressed dative singular.
local ending_stressed_dat_sg_patterns = {}
-- Set of patterns with all singular forms ending-stressed.
local ending_stressed_sg_patterns = {}
-- Set of patterns with all plural forms ending-stressed.
local ending_stressed_pl_patterns = {}
local declinable_cases_except_accusative = {
"nom_sg", "gen_sg", "dat_sg", "ins_sg", "pre_sg",
"nom_pl", "gen_pl", "dat_pl", "ins_pl", "pre_pl",
}
local accusative_cases_unsplit_animacy = {
"acc_sg", "acc_pl",
}
local accusative_cases_split_animacy = {
"acc_sg_an", "acc_sg_in", "acc_pl_an", "acc_pl_in",
}
local lemma_linked_cases = {
"nom_sg_linked", "nom_pl_linked",
}
local overridable_only_cases = {
"par", "loc", "voc", "par_pl", "loc_pl", "voc_pl", "count", "pauc",
}
local overridable_only_cases_set = m_table.listToSet(overridable_only_cases)
-- List of all cases that are declined normally.
local decl_cases = m_table.append(declinable_cases_except_accusative, accusative_cases_unsplit_animacy)
-- List of all cases that can be overridden (includes all cases except the "linked" lemma case variants). Also
-- currently the same as the cases returned by export.generate_forms().
local overridable_cases = m_table.append(decl_cases, accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases that can be displayed (includes all cases except plain accusatives).
local displayable_cases = m_table.append(declinable_cases_except_accusative, lemma_linked_cases,
accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases, including those that are declined normally (nom/gen/dat/acc/ins/pre sg and pl), plus
-- animate/inanimate accusative variants (computed automatically as appropriate from the previous cases), plus
-- additional overridable cases (loc/par/voc and plural), plus the "linked" lemma case variants used in ru-noun+
-- headwords (nom_sg_linked, nom_pl_linked, whose values come from nom_sg and nom_pl but may have additional embedded
-- links if they were given in the lemma).
local all_cases = m_table.append(overridable_cases, lemma_linked_cases)
local function english_case_description(case)
if case == "par" or case == "loc" or case == "voc" then
-- For historical reasons, the singular of these cases doens't include "_sg" in their code.
case = case .. "_sg"
end
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
par="partitive", loc="locative", voc="vocative",
count="count form", pauc="paucal form",
})
engcase = rsub(engcase, "(_[a-z]*)", {
_sg=" singular", _pl=" plural",
_an="", _in="",
--_an=" animate", _in=" inanimate"
})
return engcase
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
-- FIXME! Move below the main code
-- FIXME!! Consider deleting most of this tracking code once we've enabled
-- all the categories. Note that some of the tracking categories aren't
-- completely redundant; e.g. we have tracking pages that combine decl and
-- stress classes, such as "а/a" or "о-и/d'", which are more or less
-- equivalent to stem/gender/stress categories, but we also have the same
-- prefixed by "reducible-stem/" for reducible stems.
local function tracking_code(stress, orig_decl, decl, args, n, islast)
assert(orig_decl)
assert(decl)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
if orig_decl == decl then
orig_decl = nil
end
if args.notes then
track("notes")
end
local function all_pl_irreg()
track("irreg")
for _, case in ipairs(overridable_cases) do
if rfind(case, "_pl") then
track("irreg/" .. case)
end
end
end
local function track_prefix(prefix)
local function dotrack(suf)
track(prefix .. suf)
end
dotrack(stress)
dotrack(decl)
dotrack(decl .. "/" .. stress)
if orig_decl then
dotrack(orig_decl)
dotrack(orig_decl .. "/" .. stress)
end
for _, hint_type in ipairs(hint_types) do
dotrack(hint_type)
dotrack(decl .. "/" .. hint_type)
if orig_decl then
dotrack(orig_decl .. "/" .. hint_type)
end
end
end
track_prefix("")
if args.reducible then
track("reducible-stem")
track_prefix("reducible-stem/")
end
if rlfind(args.stem, "и́?н$") and (decl == "" or decl == "#") then
track("irregular-in")
end
if args.pltail then
track("pltail")
end
if args.sgtail then
track("sgtail")
end
if args.pltailall then
track("pltailall")
end
if args.sgtailall then
track("sgtailall")
end
if args.pl ~= args.stem then
track("irreg-pl-stem")
track("irreg")
end
if args.alt_gen_pl then
track("alt-gen-pl")
track("irreg")
track("irreg/gen_pl")
end
if args.want_sc1 then
track("want-sc1")
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-и$") or rfind(decl, "-а$") or rfind(decl, "-я$") then
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-ья$") then
track("variant-ья")
all_pl_irreg()
end
if rfind(decl, "%(ишк%)$") then
track("variant-ишко")
end
if rfind(decl, "%(ищ%)$") then
track("variant-ище")
end
if args.jo_special then
track("jo-special")
end
if args.manual then
track("manual")
end
if args.explicit_gender then
track("explicit-gender")
track("explicit-gender/" .. args.explicit_gender)
end
for _, case in ipairs(overridable_cases) do
if args[case .. n] and not args.manual then
track("override")
track("override/" .. case .. n)
track("irreg")
track("irreg/" .. case .. n)
-- questionable use: track_prefix("irreg/" .. case .. "/")
-- questionable use: track_prefix("irreg/" .. case .. n .. "/")
end
if islast and args[case] and not args.manual then
track("override")
track("override/" .. case)
track("irreg")
track("irreg/" .. case)
-- questionable use: track_prefix("irreg/" .. case .. "/")
end
if args[case .. "_tail"] then
track("casenum-tail")
track("casenum-tail/" .. case)
end
if args[case .. "_tailall"] then
track("casenum-tailall")
track("casenum-tailall/" .. case)
end
end
end
local gender_to_full = {m="ပုလ္လိၚ်", f="ဣတ္တိလိၚ်", n="နပုလ္လိၚ်"}
local gender_to_short = {m="masc", f="fem", n="neut"}
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the plural part of speech.
local function insert_category(categories, cat, pos, atbeg)
if enable_categories then
-- local fullcat = "Russian " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(categories, 1, fullcat)
else
table.insert(categories, fullcat)
end
end
end
-- Insert categories into ARGS.CATEGORIES corresponding to the specified
-- stress and declension classes and to the form of the stem (e.g. velar,
-- sibilant, etc.). Also initialize values used to compute the declension
-- heading that describes similar information. N is the number of the
-- word being processed; ISLAST is true if this is the last word.
local function categorize_and_init_heading(stress, decl, args, n, islast)
local function cat_to_list(cat)
if not cat then
return {}
elseif type(cat) == "string" then
return {cat}
else
assert(type(cat) == "table")
return cat
end
end
-- Insert category CAT into the list of categories in ARGS.
-- CAT may be nil, a single string or a list of strings. We call
-- insert_category() on each string. The strings will have "Russian "
-- prepended and "~" replaced with the plural part of speech.
local function insert_cat(cat)
for _, c in ipairs(cat_to_list(cat)) do
insert_category(args.categories, c, args.pos)
end
end
-- "Resolve" the category spec CATSPEC into the sort of category spec
-- accepted by insert_cat(), i.e. nil, a single string or a list of
-- strings. CATSPEC may be any of these or a function, which takes one
-- argument (SUFFIX) and returns another CATSPEC.
local function resolve_cat(catspec, suffix)
if type(catspec) == "function" then
return resolve_cat(catspec(suffix), suffix)
else
return catspec
end
end
-- Check whether an override for nom_sg or nom_pl still contains the
-- normal suffix (which should already have accents removed) in at least
-- one of its entries. If no override then of course we return true.
local function override_matches_suffix(args, case, n, suffix)
assert(suffix == com.remove_accents(suffix))
-- NOTE: It might not be completely correct to pass in args.forms
-- here when n == ""; this is different behavior from
-- handle_overall_forms_and_overrides(). But args.forms is only used
-- to retrieve the dat_sg for handling loc/par, and we're never
-- called with loc or par as the value of CASE, so it doesn't matter.
-- We add an assert to make sure of this.
assert(case ~= "loc" and case ~= "par")
local override = canonicalize_override(args, case, args.forms, n)
if not override then
return true
end
for _, x in ipairs(override) do
local ru, tr = x[1], x[2]
local entry, notes = m_table_tools.separate_notes(ru)
entry = com.remove_accents(m_links.remove_links(entry))
if rlfind(entry, suffix .. "$") then
return true
end
end
return false
end
if args.manual then
return
end
local h = args.heading_info
assert(decl)
local decl_cats = args.old and declensions_old_cat or declensions_cat
local sgdecl, pldecl
local is_slash_decl = rfind(decl, "/")
if is_slash_decl then
local indiv_decls = rsplit(decl, "/")
sgdecl, pldecl = indiv_decls[1], indiv_decls[2]
else
sgdecl, pldecl = decl, decl
end
local sgdc = decl_cats[sgdecl]
local pldc = decl_cats[pldecl]
assert(sgdc)
assert(pldc)
local sghint_types = com.get_stem_trailing_letter_type(
args.stem .. (sgdc.stem_suffix or ""))
-- insert English version of Zaliznyak stem type
if sgdc.decl == "indeclinable" then
insert_cat("indeclinable ~")
insert_if_not(h.stemetc, "indecl")
else
local stem_type =
sgdc.decl == "3rd" and "3rd-declension" or
m_table.contains(sghint_types, "velar") and "velar-stem" or
m_table.contains(sghint_types, "sibilant") and "sibilant-stem" or
m_table.contains(sghint_types, "c") and "ц-stem" or
m_table.contains(sghint_types, "i") and "i-stem" or
m_table.contains(sghint_types, "vowel") and "vowel-stem" or
m_table.contains(sghint_types, "soft-cons") and "vowel-stem" or
m_table.contains(sghint_types, "palatal") and "vowel-stem" or
sgdc.hard == "soft" and "soft-stem" or
"hard-stem"
local short_stem_type = stem_type == "3rd-declension" and "3rd-decl" or stem_type
if sgdc.adj then
-- Don't include gender for pluralia tantum because it's mostly
-- indeterminate (certainly when specified using a plural lemma,
-- which will be usually; technically it's partly or completely
-- determinate in certain old-style adjectives that distinguish
-- masculine from feminine/neuter, but this is too rare a case
-- to worry about)
local gendertext = args.thisn == "p" and "plural-only" or gender_to_full[sgdc.g]
insert_if_not(h.adjectival, "yes")
if args.thisn ~= "p" then
insert_if_not(h.gender, gender_to_short[sgdc.g])
end
if sgdc.possadj then
insert_cat(sgdc.decl .. " possessive " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, sgdc.decl .. " poss")
insert_if_not(h.stress, stress)
elseif stem_type == "soft-stem" or stem_type == "vowel-stem" then
insert_cat(stem_type .. " " .. gendertext .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
else
insert_cat(stem_type .. " " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
else
-- NOTE: There are 8 Zaliznyak-style stem types and 3 genders, but
-- we don't create a category for masculine-form 3rd-declension
-- nouns (there is such a noun, путь, but it mostly behaves
-- like a feminine noun), so there are 23.
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form ~")
-- NOTE: Here we are creating categories for the combination of
-- stem, gender and accent. There are 10 accent patterns and 23
-- combinations of stem and gender, which potentially makes for
-- 10*23 = 230 such categories, which is a lot. Not all such
-- categories should actually exist; there were maybe 75 former
-- declension templates, each of which was essentially categorized
-- by the same three variables, but some of which dealt with
-- ancillary issues like irregular plurals; this amounts to 67
-- actual stem/gender/accent categories, although there are more
-- of them in Zaliznyak (FIXME, how many? See generate_cats.py).
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " ~")
insert_if_not(h.adjectival, "no")
insert_if_not(h.gender, gender_to_short[sgdc.g])
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
insert_cat("~ with accent pattern " .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
local sgsuffix = args.suffixes.nom_sg
if sgsuffix then
assert(#sgsuffix == 1) -- If this ever fails, then implement a loop
sgsuffix = com.remove_accents(sgsuffix[1])
-- If we are plural only or if nom_sg is overridden and has
-- an unusual suffix, then don't create category for sg suffix
if args.thisn == "p" or not override_matches_suffix(args, "nom_sg", n, sgsuffix) or islast and not override_matches_suffix(args, "nom_sg", "", sgsuffix) then
sgsuffix = nil
end
end
local plsuffix = args.suffixes.nom_pl
if plsuffix then
assert(#plsuffix == 1) -- If this ever fails, then implement a loop
plsuffix = com.remove_accents(plsuffix[1])
-- If we are a singulare tantum or if nom_pl is overridden and has
-- an unusual suffix, then don't create category for pl suffix
if args.thisn == "s" or not override_matches_suffix(args, "nom_pl", n, plsuffix) or islast and not override_matches_suffix(args, "nom_pl", "", plsuffix) then
plsuffix = nil
end
end
sgsuffix = sgsuffix and rsub(sgsuffix, "ъ$", "")
plsuffix = plsuffix and rsub(plsuffix, "ъ$", "")
local sgcat = sgsuffix and (resolve_cat(sgdc.singular, sgsuffix) or "ending in " .. (sgsuffix == "" and "a consonant" or (sgdc.suffix and "suffix " or "") .. "-" .. sgsuffix))
local plcat = plsuffix and (resolve_cat(pldc.plural, plsuffix) or "plural -" .. plsuffix)
if sgcat and sgdc.gensg then
for _, cat in ipairs(cat_to_list(sgcat)) do
insert_cat("~ " .. cat)
end
end
if sgcat and plcat and (sgdc.suffix or sgdc.alt_nom_pl or sgdc.irregpl or
is_slash_decl and plsuffix == "-ья") then
for _, scat in ipairs(cat_to_list(sgcat)) do
for _, pcat in ipairs(cat_to_list(plcat)) do
-- insert_cat("~ " .. scat .. " with " .. pcat)
end
end
end
if args.pl ~= args.stem then
-- insert_cat("~ with irregular plural stem")
end
if args.reducible and not sgdc.ignore_reduce then
-- insert_cat("~ with reducible stem")
if args.soft_n then
-- insert_cat("~ with soft final н in reduced stem")
end
insert_if_not(h.reducible, "yes")
else
insert_if_not(h.reducible, "no")
end
if args.alt_gen_pl then
-- insert_cat("~ with alternative genitive plural")
end
if sgdc.adj then
-- insert_cat("adjectival ~")
end
end
local function compute_heading(args)
local headings = {}
local h = args.heading_info
table.insert(headings, args.a == "a" and "anim" or args.a == "i" and
"inan" or "bian")
table.insert(headings, args.nonumber and "uncountable" or
args.n == "s" and "sg-only" or args.n == "p" and "pl-only" or nil)
if #h.gender > 0 then
table.insert(headings, table.concat(h.gender, "/") .. "-form")
end
if #h.stemetc > 0 then
table.insert(headings, table.concat(h.stemetc, "/"))
end
if #h.stress > 0 then
local stresses = {}
for _, stress in ipairs(h.stress) do
table.insert(stresses, (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
table.insert(headings, "accent-" .. table.concat(stresses, "/"))
end
local function handle_bool(boolvals, text, into)
into = into or headings
if m_table.contains(boolvals, "yes") and m_table.contains(boolvals, "no") then
table.insert(into, "[" .. text .. "]")
elseif m_table.contains(boolvals, "yes") then
table.insert(into, text)
end
end
handle_bool(h.adjectival, "adj")
handle_bool(h.reducible, "reduc")
return headings
end
local function compute_overall_heading_categories_and_genders(args)
local hinfo = args.per_word_heading_info
local index = 0
-- First try for non-adjectival, non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") and not m_table.contains(hinfo[i].adjectival, "yes") then
index = i
break
end
end
if index == 0 then
-- Then just non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") then
index = i
break
end
end
end
-- Finally, do anything
if index == 0 then
index = 1
end
-- Compute final heading
local headings = args.per_word_headings[index]
local categories = args.per_word_categories[index]
if args.any_irreg then
table.insert(headings, "irreg")
-- insert_category(categories, "irregular ~", args.pos)
end
for _, case in ipairs(overridable_cases) do
local is_pl = rfind(case, "_pl")
if args.n == "s" and is_pl or args.n == "p" and not is_pl then
-- Don't create singular categories when plural-only or vice-versa
elseif overridable_only_cases_set[case] then
if args.any_overridden[case] then
-- insert_category(categories, "~ with " .. english_case_description(case), args.pos)
end
elseif args.any_irreg_case[case] then
-- insert_category(categories, "~ with irregular " .. english_case_description(case), args.pos)
end
end
local heading = args.manual and "" or "(<span style=\"font-size: smaller;\">[[Appendix:Russian nouns#Declension tables|" .. table.concat(headings, " ") .. "]]</span>)"
args.heading = heading
args.categories = categories
args.genders = args.per_word_genders[index]
end
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Used by do_generate_forms().
local function arg1_is_stress(arg1)
if not arg1 then return false end
for _, arg in ipairs(rsplit(arg1, ",")) do
if not rfind(arg, "^[a-f]'?'?$") then
return false
end
end
return true
end
-- Used by do_generate_forms(), handling a word joiner argument
-- of the form 'join:JOINER'.
local function extract_word_joiner(spec)
word_joiner = rmatch(spec, "^join:(.*)$")
assert(word_joiner)
return com.split_russian_tr(word_joiner, "dopair")
end
local function determine_headword_gender(args, sgdc, gender)
-- If gender unspecified, use normal gender of declension, except when
-- adjectival nouns that are pluralia tantum, where the gender is
-- mostly indeterminate (FIXME, not completely with old-style declensions
-- but we don't handle that currently).
if not gender then
if sgdc.adj and args.thisn == "p" then
gender = nil
else
gender = sgdc.g
end
end
-- Determine headword genders
gender = gender and gender ~= "none" and gender .. "-" or ""
local plsuffix = args.n == "p" and "-p" or ""
local hgens
if args.a == "a" then
hgens = {gender .. "an" .. plsuffix}
elseif args.a == "i" then
hgens = {gender .. "in" .. plsuffix}
elseif args.a == "ai" then
hgens = {gender .. "an" .. plsuffix, gender .. "in" .. plsuffix}
else
hgens = {gender .. "in" .. plsuffix, gender .. "an" .. plsuffix}
end
-- Insert into list of genders
for _, hgen in ipairs(hgens) do
insert_if_not(args.genders, hgen)
end
end
function export.do_generate_forms(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SETS and JOINER, where ARG_SETS
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Gather arguments into a list of ARG_SET objects, containing (potentially)
-- elements 1, 2, 3, 4, corresponding to accent pattern, stem, declension
-- type, pl stem and coming from consecutive numbered parameters. Sets of
-- declension parameters are separated by the word "or".
local arg_sets = {}
-- Find maximum-numbered arg, allowing for holes
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Now gather the arguments.
local offset = 0
local arg_set = {}
for i=1,(max_arg + 1) do
local end_arg_set = false
local end_word = false -- FIXME, is this correct?
local word_joiner
if i == max_arg + 1 then
end_arg_set = true
end_word = true
word_joiner = {""}
elseif args[i] == "_" then
end_arg_set = true
end_word = true
word_joiner = {" "}
elseif args[i] == "-" then
end_arg_set = true
end_word = true
word_joiner = {"-"}
elseif args[i] and rfind(args[i], "^join:") then
end_arg_set = true
end_word = true
word_joiner = extract_word_joiner(args[i])
elseif args[i] == "or" then
end_arg_set = true
end
if end_arg_set then
table.insert(arg_sets, arg_set)
arg_set = {}
offset = i
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
else
-- If the first argument isn't stress, that means all arguments
-- have been shifted to the left one. We want to shift them
-- back to the right one, so we change the offset so that we
-- get the same effect of skipping a slot in the arg set.
if i - offset == 1 and not arg1_is_stress(args[i]) then
offset = offset - 1
end
if i - offset > 4 then
error("Too many arguments for argument set: arg " .. i .. " = " .. (args[i] or "(blank)"))
end
arg_set[i - offset] = args[i]
end
end
return generate_forms_1(args, per_word_info)
end
function export.do_generate_forms_multi(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SET and JOINER, where ARG_SET
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Find maximum-numbered arg, allowing for holes (FIXME: Is this needed
-- here? Will there be holes?)
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Gather arguments into a list of ARG_SET objects, containing
-- (potentially) elements 1, 2, 3, corresponding to accent pattern,
-- lemma+declension spec, pl stem, exactly as with do_generate_forms()
-- and {{ru-noun-table}} except that the values come from a single argument
-- of the form ACCENTPATTERN:LEMMADECL:PL where all but LEMMADECL may (and
-- probably will be) omitted and LEMMADECL may be of the following forms:
-- LEMMA (for a noun with empty decl spec),
-- LEMMADECL (for a noun with non-empty decl spec beginning with a
-- *, left paren or semicolon),
-- LEMMA^DECL (for a noun with non-empty decl spec),
-- LEMMA$ (for an indeclinable word)
-- LEMMA+ (for an adjective with auto-detected decl class)
-- LEMMA+DECL (for an adjective with explicit decl class)
-- Sets of parameters for the same word are separated by the word "or".
local arg_sets = {}
local continue_arg_sets = true
for i=1,(max_arg + 1) do
local end_word = false
local word_joiner
local process_arg = false
if i == max_arg + 1 then
end_word = true
word_joiner = {""}
elseif args[i] == "-" then
end_word = true
word_joiner = {"-"}
continue_arg_sets = true
elseif rfind(args[i], "^join:") then
end_word = true
word_joiner = extract_word_joiner(args[i])
continue_arg_sets = true
elseif args[i] == "or" then
continue_arg_sets = true
else
if continue_arg_sets then
continue_arg_sets = false
else
end_word = true
word_joiner = {" "}
end
process_arg = true
end
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
if process_arg then
local vals = rsplit(args[i], ":")
if #vals > 3 then
error("Can't specify more than 3 colon-separated params of param set: " .. args[i])
end
local arg_set = {}
if arg1_is_stress(vals[1]) then
arg_set[1] = vals[1]
arg_set[2] = vals[2]
arg_set[4] = vals[3]
else
arg_set[2] = vals[1]
arg_set[4] = vals[2]
end
-- recognize indeclinable
local indecl_stem = rmatch(arg_set[2], "^(.-)%$$")
if indecl_stem then
arg_set[2] = indecl_stem
arg_set[3] = "$"
else
-- recognize adjective
local adj_stem, adj_type = rmatch(arg_set[2], "^(.*)(%+.*)$")
if adj_stem then
arg_set[2] = adj_stem
arg_set[3] = adj_type
else
-- recognize noun with ^
local noun_stem, noun_type = rmatch(arg_set[2], "^(.*)%^(.*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- recognize noun without ^ but with decl spec
noun_stem, noun_type = rmatch(arg_set[2], "^(..-)([;*(].*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- noun without ^ or decl spec; nothing to do
end
end
end
end
table.insert(arg_sets, arg_set)
end
end
return generate_forms_1(args, per_word_info)
end
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence.
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence,
-- as well as show_z() for template {{ru-decl-noun-z}}, which has a
-- subset of the functionality of the other two.
generate_forms_1 = function(args, per_word_info)
local orig_args
if test_new_ru_noun_module then
orig_args = mw.clone(args)
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local old = args.old
local function verify_animacy_value(val)
if not val then return nil end
if val == "a" or val == "an" or val == "anim" then
return "a"
elseif val == "i" or val == "in" or val == "inan" then
return "i"
elseif val == "b" or val == "bi" or val == "both" or val == "ai" then
return "ai"
elseif val == "ia" then
return "ia"
end
error("Animacy value " .. val .. " should be empty or a/an/anim (animate), i/in/inan (inanimate), b/bi/both/ai (bianimate, listing animate first), or ia (bianimate, listing inanimate first)")
return nil
end
local function verify_number_value(val, allow_none)
if not val then return nil end
local short = usub(val, 1, 1)
if short == "s" or short == "p" or short == "b" or (allow_none and short == "n" or false) then
return short
end
if allow_none then
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), 'b' (both) or 'n' (none)")
else
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), or 'b' (both)")
end
return nil
end
-- Verify and canonicalize animacy, number, prefix, suffix
assert(#per_word_info >= 1)
for i=1,#per_word_info do
args["a" .. i] = verify_animacy_value(args["a" .. i])
args["n" .. i] = verify_number_value(args["n" .. i])
args["prefix" .. i] = com.split_russian_tr(args["prefix" .. i] or "", "dopair")
args["suffix" .. i] = com.split_russian_tr(args["suffix" .. i] or "", "dopair")
end
args.a = verify_animacy_value(args.a) or "i"
-- args.ndef, if set, is the default value for args.n; if unset, it defaults
-- to "both". It is set to "singular" in ru-proper noun+. We store the value
-- of args.n in args.orign before defaulting to args.ndef because we may
-- change it to plural-only later on if it was unspecified (this happens if
-- an individual word's lemma is plural), and to determine whether it was
-- unspecified, we need the original value before defaulting.
args.n = verify_number_value(args.n, "allow none")
-- treat n=none like n=sg but set a flag so "singular" isn't displayed
if args.n == "n" then
args.n = "s"
args.nonumber = true
end
args.ndef = verify_number_value(args.ndef)
args.orign = args.n
args.n = args.n or args.ndef
args.prefix = com.split_russian_tr(args.prefix or "", "dopair")
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
-- Attach overall prefix to first per-word prefix, similarly for suffix
args.prefix1 = com.concat_paired_russian_tr(args.prefix, args.prefix1)
args["suffix" .. #per_word_info] = com.concat_paired_russian_tr(
args["suffix" .. #per_word_info], args.suffix)
-- Initialize non-word-specific arguments.
--
-- The following is a list of WORD_INFO items, one per word, each of
-- which is a two element list of WORD_FORMS (a table listing the forms for
-- each case) and JOINER (a string, indicating how to join the word with
-- the next one).
args.per_word_info = {}
-- List of HEADING_INFO items, one per word, containing the raw material
-- used to generate the header. Initialized from 'args.heading_info',
-- which is initialized in categorize_and_init_heading().
args.per_word_heading_info = {}
-- List of CATEGORIES items, one per word, containing the categories
-- used to initialize the page categories. Initialized from
-- 'args.categories', which is initialized in categorize_and_init_heading().
args.per_word_categories = {}
-- List of HEADINGS items, one per word, containing the actual words that
-- go into the header if we were to use that word to construct the header.
-- Comes from compute_heading(). We use this to generate the actual header
-- string, which goes into 'args.heading' at the end (done in
-- compute_overall_heading_categories_and_genders()).
args.per_word_headings = {}
-- List of GENDERS items, one per word, containing the headword genders
-- for each word (where "headword gender" is in the format used in
-- headwords and actually includes animacy and number as well, e.g.
-- 'm-in' or 'f-an-p'). We end up selecting one such item and putting
-- it into 'args.genders' at the end
-- (in compute_overall_heading_categories_and_genders()).
args.per_word_genders = {}
args.any_overridden = {}
args.any_non_nil = {}
args.any_irreg = false
args.any_irreg_case = {}
local function insert_cat(cat)
insert_category(args.categories, cat, args.pos)
end
args.internal_notes = {}
local decl_sufs = old and declensions_old or declensions
local decl_cats = old and declensions_old_cat or declensions_cat
local intable = old and internal_notes_table_old or internal_notes_table
-- Default lemma defaults to previous lemma, first one to page name.
-- FIXME: With multiple words, we should probably split the page name
-- on spaces and default each word in turn
local default_lemma
local all_stresses_seen
-- Made into a function to avoid having to indent a lot of code.
-- Process a single arg set of a single word. This inserts the forms
-- for the word into args.forms and sets categories and tracking pages.
local function do_arg_set(arg_set, n, islast)
local stress_arg = arg_set[1]
local decl = arg_set[3] or ""
local pl, pltr
if arg_set[4] then
pl, pltr = com.split_russian_tr(arg_set[4])
end
-- Extract special markers from declension class.
if decl == "manual" then
decl = "$"
args.manual = true
if #per_word_info > 1 or #per_word_info[1][1] > 1 then
error("Can't specify multiple words or argument sets when manual")
end
if pl then
error("Can't specify optional stem parameters when manual")
end
end
decl, args.jo_special = rsubb(decl, "([^/%a])ё$", "%1")
if not args.jo_special then
decl, args.jo_special = rsubb(decl, "([^/%a])ё([^/%a])", "%1%2")
end
decl, args.want_sc1 = rsubb(decl, "%(1%)", "")
decl, args.alt_gen_pl = rsubb(decl, "%(2%)", "")
decl, args.reducible = rsubb(decl, "%*", "")
decl, args.soft_n = rsubb(decl, "%(нь%)", "")
decl = rsub(decl, ";", "")
-- Get the lemma.
local lemma = args.manual and "-" or arg_set[2] or default_lemma
if not lemma then
error("Lemma in first argument set must be specified")
end
default_lemma = lemma
local lemmatr
lemma, lemmatr = com.split_russian_tr(lemma)
-- If we're conjugating a suffix, insert a pseudoconsonant at the beginning
-- of all forms, so they get conjugated as if ending in a consonant.
-- We remove the pseudoconsonant later.
local is_suffix = lemma ~= "-" and rfind(lemma, "^%-")
args.any_suffix = args.any_suffix or is_suffix
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or is_suffix and PSEUDOCONS
if asif_prefix then
lemma = rsub(lemma, "^%-", "-" .. asif_prefix)
if lemmatr then
lemmatr = rsub(lemmatr, "^%-", "-" .. com.translit(asif_prefix))
end
end
args.thisa = args["a" .. n] or args.a
args.thisn = args["n" .. n] or args.n
-- Check for explicit allow-unaccented indication.
local allow_unaccented
lemma, allow_unaccented = rsubb(lemma, "^%*", "")
args.allow_unaccented = args.allow_unaccented or allow_unaccented
if args.allow_unaccented then
track("allow-unaccented")
end
args.orig_lemma = lemma
lemma = m_links.remove_links(lemma)
args.lemma_no_links = lemma
args.lemmatr = lemmatr
if args.lemma then
-- Explicit lemma given.
args.explicit_lemma, args.explicit_lemmatr = com.split_russian_tr(args.lemma)
end
-- Treat suffixes without an accent, and suffixes with an accent on the
-- initial hyphen, as if they were preceded with a *, which overrides
-- all the logic that normally (a) normalizes the accent, and (b)
-- complains about multisyllabic words without an accent. Don't do this
-- if lemma is just -, which is used specially in manual declension
-- tables (e.g. сто, три).
if lemma ~= "-" and (rfind(lemma, "^%-" .. AC) or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
-- Convert lemma and decl arg into stem and canonicalized decl.
-- This will autodetect the declension from the lemma if an explicit
-- decl isn't given.
local stem, tr, gender, was_accented, was_plural, was_autodetected
if rfind(decl, "^%+") then
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
detect_adj_type(lemma, lemmatr, decl, old)
else
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
determine_decl(lemma, lemmatr, decl, args)
end
if was_plural then
args.n = args.orign or "p"
args.thisn = args["n" .. n] or args.n
elseif decl ~= "$" then
args.thisn = args.thisn or "b"
end
args.explicit_gender = gender
-- If allow-unaccented not given, maybe check for missing accents.
if not args.allow_unaccented and not stress_arg and was_autodetected and com.needs_accents(lemma) then
-- If user gave the full word and expects us to determine the
-- declension and stress, the word should have an accent on the
-- stem or ending. We have a separate check farther below for
-- an accent on a multisyllabic stem, after stripping off any
-- ending; but this way we get an error if the user e.g. writes
-- "гора" without an accent rather than assuming it's stem
-- stressed, as would otherwise happen.
error("Lemma must have an accent in it: " .. lemma)
end
-- If stress not given, auto-determine; else validate/canonicalize
-- stress arg, override in certain cases and convert to list.
if not stress_arg then
stress_arg = {detect_stress_pattern(stem, decl, decl_cats, args.reducible, was_plural, was_accented)}
else
stress_arg = rsplit(stress_arg, ",")
for i=1,#stress_arg do
local stress = stress_arg[i]
stress = override_stress_pattern(decl, stress)
if not stress_patterns[stress] then
error("Unrecognized accent pattern " .. stress)
end
stress_arg[i] = stress
end
end
-- parse slash decl to list
local sub_decls
if rfind(decl, "/") then
track("mixed-decl")
insert_cat("~ with mixed declension")
local indiv_decls = rsplit(decl, "/")
-- Should have been caught in canonicalize_decl()
assert(#indiv_decls == 2)
sub_decls = {{indiv_decls[1], "sg"}, {indiv_decls[2], "pl"}}
else
sub_decls = {{decl}}
end
-- Get singular declension and corresponding category.
local sgdecl = sub_decls[1][1]
local sgdc = decl_cats[sgdecl]
assert(sgdc)
-- Compute headword gender(s). We base it off the singular declension
-- if we have a slash declension -- it's the best we can do.
determine_headword_gender(args, sgdc, gender)
local original_stem, original_tr = stem, tr
local original_pl, original_pltr = pl, pltr
-- Loop over accent patterns in case more than one given.
for _, stress in ipairs(stress_arg) do
args.suffixes = {}
stem, tr = original_stem, original_tr
local bare, baretr
local stem_for_bare, tr_for_bare
pl, pltr = original_pl, original_pltr
insert_if_not(all_stresses_seen, stress)
local stem_was_unstressed = com.is_unstressed(stem)
-- If special case ;ё was given and stem is unstressed,
-- add ё to the stem now; but don't let this interfere with
-- restressing, to handle cases like железа́ with gen pl желёз
-- but nom pl же́лезы.
if stem_was_unstressed and args.jo_special then
-- Beware, Cyrillic еЕ in first rsub, Latin eE in second
local new_stem = rsub(stem, "([еЕ])([^еЕ]*)$",
function(e, rest)
return (e == "Е" and "Ё" or "ё") .. rest
end
)
if stem == new_stem then
error("No е in stem to replace with ё")
end
stem = new_stem
if tr then
local subbed
-- e after j -> o, e not after j -> jo; don't just convert e -> jo
-- and then map jjo -> jo because we want to preserve double j
tr, subbed = rsubb(tr, "([jJ])([eE])([^eE]*)$",
function(j, e, rest)
return j .. (e == "E" and "O" or "o") .. AC .. rest
end
)
if not subbed then
tr = rsub(tr, "([eE])([^eE]*)$",
function(e, rest)
return (e == "E" and "Jo" or "jo") .. AC .. rest
end
)
end
tr = com.j_correction(tr)
end
-- This is used to handle железа́ with gen pl желёз and nom pl
-- же́лезы. We have two stressed stems, one for the gen pl and
-- one for the remaining pl cases, and the variable 'stem' can
-- handle only one, so we put the second (gen pl) stem in
-- stem_for_bare, which goes into the value of 'bare' (used
-- only for gen pl here).
stem_for_bare, tr_for_bare = stem, tr
end
-- Maybe add stress to the stem, depending on whether the
-- stem was unstressed and the stress pattern. Stem pattern f
-- and variants call for initial stress (голова́ -> го́ловы);
-- stem pattern d and variants call for stem-final stress
-- (сапожо́к -> сапо́жки). Stem patterns b and b' apparently
-- call for stem-final stress as well but it's unlikely to
-- make much of a difference (pattern b' only occurs in 3rd-decl
-- feminines, which should already have stress in the stem,
-- and the only place pattern b gets stem stress is in bare
-- forms, i.e. nom sg and/or gen pl depending on the decl type,
-- and nom sg stress should already be in the lemma while
-- gen pl stress is handled by a different ending-stressing
-- mechanism in attach_unstressed(); however, the user is
-- free to leave a masc or 3rd-decl fem lemma completely
-- unstressed with pattern b, and then the stem-final stress
-- *will* make a difference).
local function restress_stem(stem, tr, stress, stem_unstressed)
-- If the user has indicated they purposely are leaving the
-- word unstressed by putting a * at the beginning of the main
-- stem, leave it unstressed. This might indicate lack of
-- knowledge of the stress or a truly unaccented word
-- (e.g. an unaccented suffix).
if args.allow_unaccented then
return stem, tr
end
if tr and com.is_unstressed(stem) ~= com.is_unstressed(tr) then
error("Stem " .. stem .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(stem) then
stem, tr = com.make_ending_stressed(stem, tr)
-- For those patterns that are ending-stressed in the singular
-- nominative (and hence are likely to be expressed without an
-- accent on the stem) it's safe to put a particular accent on
-- the stem depending on the stress type. Otherwise, give an
-- error if no accent.
elseif stem_unstressed then
if rfind(stress, "^f") then
stem, tr = com.make_beginning_stressed(stem, tr)
elseif (rfind(stress, "^[bd]") or
args.thisn == "p" and ending_stressed_pl_patterns[stress]) then
stem, tr = com.make_ending_stressed(stem, tr)
elseif com.needs_accents(stem) then
error("Stem " .. stem .. " requires an accent")
end
end
return stem, tr
end
stem, tr = restress_stem(stem, tr, stress, stem_was_unstressed)
-- Leave pl unaccented if user wants this; see restress_stem().
if pl and not args.allow_unaccented then
if pltr and com.is_unstressed(pl) ~= com.is_unstressed(pltr) then
error("Plural stem " .. pl .. " and translit " .. pltr .. " must have same accent pattern")
end
if com.is_monosyllabic(pl) then
pl, pltr = com.make_ending_stressed(pl, pltr)
end
-- I think this is safe.
if com.needs_accents(pl) then
if ending_stressed_pl_patterns[stress] then
pl, pltr = com.make_ending_stressed(pl, pltr)
elseif not args.allow_unaccented then
error("Plural stem " .. pl .. " requires an accent")
end
end
end
local resolved_bare, resolved_baretr
-- Handle (de)reducibles
-- FIXME! We are dereducing based on the singular declension.
-- In a slash declension things can get weird and we don't
-- handle that. We are also computing the bare value from the
-- singular stem, and again things can get weird with a plural
-- stem. Note that we don't compute a bare value unless we have
-- to (either (de)reducible or stress pattern f/f'/f'' combined
-- with ё special case); the remaining times we generate the bare
-- value directly from the plural stem.
if args.reducible and not sgdc.ignore_reduce then
-- Zaliznyak treats all nouns in -ье and -ья as being
-- reducible. We handle this automatically and don't require
-- the user to specify this, but ignore it if so for
-- compatibility.
if is_reducible(sgdc) then
-- If we derived the stem from a nom pl form, then
-- it's already reduced, and we need to dereduce it to
-- get a bare form; otherwise the stem comes from the
-- nom sg and we need to reduce it to get the real stem.
if was_plural then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
resolved_bare, resolved_baretr = stem, tr
stem, tr = export.reduce_nom_sg_stem(stem, tr,
sgdecl, args.soft_n, "error")
-- Stem will be unstressed if stress was on elided
-- vowel; restress stem the way we did above. (This is
-- needed in at least one word, сапожо́к 3*d(2), with
-- plural stem probably сапо́жк- and gen pl probably
-- сапо́жек.)
stem, tr = restress_stem(stem, tr, stress,
com.is_unstressed(stem))
if stress ~= "a" and stress ~= "b" and args.alt_gen_pl and not pl then
-- Nouns like рожо́к, глазо́к of type 3*d(2) have
-- gen pl's ро́жек, гла́зок; to handle this,
-- dereduce the reduced stem and store in a
-- special place.
args.gen_pl_bare, args.gen_pl_baretr =
export.dereduce_nom_sg_stem(stem, tr,
sgdc, stress, old, "error")
end
end
elseif is_dereducible(sgdc) then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
error("Declension class " .. sgdecl .. " not (de)reducible")
end
elseif stem_for_bare and stem ~= stem_for_bare then
resolved_bare, resolved_baretr =
add_bare_suffix(stem_for_bare, tr_for_bare, old, sgdc, false)
end
-- Leave unaccented if user wants this; see restress_stem().
-- FIXME, we no longer allow the user to specify the bare value
-- so it's unclear if this is needed any more.
if resolved_bare and not args.allow_unaccented then
if resolved_baretr and com.is_unstressed(resolved_bare) ~= com.is_unstressed(resolved_baretr) then
error("Resolved bare stem " .. resolved_bare .. " and translit " .. resolved_baretr .. " must have same accent pattern")
end
if com.is_monosyllabic(resolved_bare) then
resolved_bare, resolved_baretr =
com.make_ending_stressed(resolved_bare, resolved_baretr)
else
if com.needs_accents(resolved_bare) then
error("Resolved bare stem " .. resolved_bare .. " requires an accent")
end
end
end
args.stem, args.stemtr = stem, tr
args.bare, args.baretr = resolved_bare, resolved_baretr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, tr)
if pl then
args.pl, args.pltr = pl, pltr
else
args.pl, args.pltr = stem, tr
end
args.upl, args.upltr = com.make_unstressed_once(args.pl, args.pltr)
-- Special hack for любо́вь and other reducible 3rd-fem nouns,
-- which have the full stem in the ins sg
args.ins_sg_stem = sgdecl == "ь-f" and args.reducible and resolved_bare
args.ins_sg_tr = sgdecl == "ь-f" and args.reducible and resolved_baretr
-- Loop over declension classes (we may have two of them, one for
-- singular and one for plural, in the case of a mixed declension
-- class of the form SGDECL/PLDECL).
for _,decl_spec in ipairs(sub_decls) do
local orig_decl = decl_spec[1]
local number = decl_spec[2]
local real_decl =
determine_stress_variant(orig_decl, stress)
real_decl = determine_stem_variant(real_decl,
number == "pl" and args.pl or args.stem)
-- sanity checking; errors should have been caught in
-- canonicalize_decl()
assert(decl_cats[real_decl], "real_decl " .. real_decl .. " nonexistent")
assert(decl_sufs[real_decl], "real_decl " .. real_decl .. " nonexistent")
tracking_code(stress, orig_decl, real_decl, args, n, islast)
do_stress_pattern(stress, args, real_decl, number, n, islast)
-- handle internal notes
local internal_note = intable[real_decl]
if internal_note then
insert_if_not(args.internal_notes, internal_note)
end
end
categorize_and_init_heading(stress, decl, args, n, islast)
end
end
local n = 0
for _, word_info in ipairs(per_word_info) do
n = n + 1
local islast = n == #per_word_info
local arg_sets, joiner = word_info[1], word_info[2]
args.forms = {}
args.heading_info = {animacy={}, number={}, gender={}, stress={},
stemetc={}, adjectival={}, reducible={}}
args.categories = {}
args.genders = {}
args.this_any_non_nil = {}
args.any_suffix = false
if #arg_sets > 1 then
track("multiple-arg-sets")
-- insert_cat("~ with multiple argument sets")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
default_lemma = pagename
all_stresses_seen = {}
-- Loop over all arg sets.
for _, arg_set in ipairs(arg_sets) do
do_arg_set(arg_set, n, islast)
end
if #all_stresses_seen > 1 then
track("multiple-accent-patterns")
-- insert_cat("~ with multiple accent patterns")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
table.insert(args.per_word_heading_info, args.heading_info)
table.insert(args.per_word_categories, args.categories)
local headings = compute_heading(args)
table.insert(args.per_word_headings, headings)
table.insert(args.per_word_genders, args.genders)
handle_forms_and_overrides(args, n, islast)
if args.any_suffix then
-- If we're conjugating a suffix, remove the pseudoconsonant or asif_prefix
-- that we previously inserted at the beginning.
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or PSEUDOCONS
local asif_prefix_tr = com.translit(asif_prefix)
for _, case in ipairs(all_cases) do
if args.forms[case] then
local newforms = {}
for _, form in ipairs(args.forms[case]) do
local formru = form[1]
local formtr = form[2]
formru = rsub(formru, "^%-" .. asif_prefix, "-")
if formtr then
formtr = rsub(formtr, "^%-" .. asif_prefix_tr, "-")
end
if formru == "-" then
-- if no ending, insert "(no suffix)".
table.insert(newforms, {"(no suffix)"})
else
table.insert(newforms, {formru, formtr})
end
end
args.forms[case] = newforms
end
end
end
table.insert(args.per_word_info, {args.forms, joiner})
end
handle_overall_forms_and_overrides(args)
compute_overall_heading_categories_and_genders(args)
for _, case in ipairs(all_cases) do
if args[case] then
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
ruentry = m_links.remove_links(ruentry)
if rfind(ulower(ruentry), latin_text_class) then
--error("Found Latin text " .. ruentry .. " in case " .. case)
track("latin-text")
track("latin-text/" .. case)
end
end
end
end
-- Test code to compare existing module to new one.
if test_new_ru_noun_module then
local m_new_ru_noun = require("Module:User:Benwing2/ru-noun")
local newargs = m_new_ru_noun.do_generate_forms(orig_args, old)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
local is_pl = rfind(case, "_pl")
if args.thisn == "s" and is_pl or args.thisn == "p" and not is_pl then
-- Don't need to check cases that won't be displayed.
elseif not m_table.deepEquals(arg, newarg) then
local monosyl_accent_diff = false
-- Differences only in monosyllabic accents. Enable if we
-- change the algorithm for these.
--if arg and newarg and #arg == 1 and #newarg == 1 then
-- local ru1, tr1 = arg[1][1], arg[1][2]
-- local ru2, tr2 = newarg[1][1], newarg[1][2]
-- if com.is_monosyllabic(ru1) and com.is_monosyllabic(ru2) then
-- ru1, tr1 = com.remove_accents(ru1, tr1)
-- ru2, tr2 = com.remove_accents(ru2, tr2)
-- if ru1 == ru2 and tr1 == tr2 then
-- monosyl_accent_diff = true
-- end
-- end
--end
if monosyl_accent_diff then
track("monosyl-accent-diff")
difdecl = true
else
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
end
if not difdecl then track("same-decl") end
end
return args
end
-- Implementation of main entry point
local function do_show(frame, old)
local args = clone_args(frame)
local args = export.do_generate_forms(args, old)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- Implementation of new entry point, esp. for multiple words
local function do_show_multi(frame)
local args = clone_args(frame)
local args = export.do_generate_forms_multi(args)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The new entry point, esp. for multiple words (but works fine for
-- single words).
function export.show_multi(frame)
return do_show_multi(frame)
end
local function get_form(forms, preserve_links, raw)
local canon_forms = {}
for _, form in ipairs(forms) do
if raw then
local ru, tr = form[1], form[2]
ru = rsub(ru, "|", "<!>")
if tr then
tr = rsub(tr, "|", "<!>")
end
insert_if_not(canon_forms, {ru, tr})
else
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
-- Skip hypothetical forms (but include in the raw versions)
if not rfind(runotes, HYPMARKER) then
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
end
if not preserve_links then
ruentry = m_links.remove_links(ruentry)
end
ruentry = rsub(ruentry, "|", "<!>")
if trentry then
trentry = rsub(trentry, "|", "<!>")
end
insert_if_not(canon_forms, {ruentry, trentry})
end
end
end
return com.concat_forms(canon_forms)
end
local function case_will_be_displayed(args, case)
local ispl = rfind(case, "_pl")
local caseok = true
if args.n == "p" then
caseok = ispl
elseif args.n == "s" then
caseok = not ispl
end
for _, override_case in ipairs(overridable_only_cases) do
if case == override_case and not args.any_overridden[override_case] then
caseok = false
break
end
end
if args.a == "a" or args.a == "i" then
if rfind(case, "_[ai]n") then
caseok = false
end
else -- bianimate
-- don't include inanimate/animate variants if combined variant exists
-- (typically because inanimate/animate variants are the same);
-- FIXME: This could conceivably be different from how the display
-- code works, which just checks that the inanimate/animate variants
-- are the same when deciding whether to display them, in particular
-- if there is an override. Here we are following the algorithm of
-- handle_overall_forms_and_overrides().
if (case == "acc_sg_in" or case == "acc_sg_an") and args.acc_sg or
(case == "acc_pl_in" or case == "acc_pl_an") and args.acc_pl then
caseok = false
end
end
if not args[case] then
caseok = false
end
return caseok
end
local function concat_case_args(args, do_all, raw)
local ins_text = {}
for _, case in ipairs(do_all and all_cases or overridable_cases) do
if case_will_be_displayed(args, case) then
local forms = get_form(args[case], rfind(case, "_linked"), raw)
if forms ~= "" then
table.insert(ins_text, case .. (raw and "_raw" or "") .. "=" ..
forms)
end
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-noun-forms' to generate all noun forms.
-- This returns a single string, with | separating arguments and named
-- arguments of the form NAME=VALUE.
function export.generate_forms(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
return concat_case_args(args)
end
-- The entry point to generate multiple sets of noun forms. This is a hack
-- to speed up calling from a bot, where we often want to compare old and new
-- argument results to make sure they're the same. Each set of arguments is
-- jammed together into a single argument with individual values separated by
-- <!>; named arguments are of the form NAME<->VALUE. The return value for
-- each set of arguments is as in export.generate_forms(), and the return
-- values are concatenated with <!> separating them. NOTE: This will fail if
-- the exact sequences <!> or <-> happen to occur in values (which is unlikely,
-- esp. as we don't even use the characters <, ! or > for anything) and aren't
-- HTML-escaped.
function export.generate_multi_forms(frame)
local retvals = {}
for _, argset in ipairs(frame.args) do
local args = {}
local i = 0
local argvals = rsplit(argset, "<!>")
for _, argval in ipairs(argvals) do
local split_arg = rsplit(argval, "<%->")
if #split_arg == 1 then
i = i + 1
args[i] = ine(split_arg[1])
else
assert(#split_arg == 2)
args[split_arg[1]] = ine(split_arg[2])
end
end
args = export.do_generate_forms(args, false)
table.insert(retvals, concat_case_args(args))
end
return table.concat(retvals, "<!>")
end
-- The entry point for 'ru-noun-form' to generate a particular noun form.
function export.generate_form(frame)
local args = clone_args(frame)
if not args.form then
error("Must specify desired form using form=")
end
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
local args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
-- The entry point for generating arguments of various sorts, including
-- the case forms, gender, number and animacy.
function export.generate_args(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
local retargs = {}
table.insert(retargs, concat_case_args(args, "doall"))
table.insert(retargs, concat_case_args(args, "doall", "raw"))
table.insert(retargs, "g=" .. table.concat(args.genders, ","))
-- The following is correct even with ndef because if ndef is
-- set we will set it in args.n.
table.insert(retargs, "n=" .. (args.n or "b"))
table.insert(retargs, "a=" .. (args.a or "i"))
return table.concat(retargs, "|")
end
-- The entry point for compatibility with {{ru-decl-noun-z}}.
function export.show_z(frame)
local args = clone_args(frame)
local stem = args[1]
local stress = args[2]
local specific = args[4] or ""
-- Parse gender/animacy spec
local gender, anim = rmatch(args[3], "^([mfn])-([a-z]+)")
if not gender then
error("Unrecognized gender/anim spec " .. args[3])
end
if anim ~= "an" and anim ~= "in" then anim = "both" end
args.a = anim
-- Handle specific
specific = rsub(specific, "ё", ";ё")
-- Compute decl; special case for семьянин (perhaps not necessary)
local decl = com.make_unstressed_once(stem) == "семьянин" and "#" .. specific or gender .. specific
-- Handle overrides
args.pre_sg = args.prp_sg
args.pre_pl = args.prp_pl
args.notes = args.note
if args.par then
args.par = "+"
end
if args.loc then
if args.loc == "в" then
args.loc = "в +"
elseif args.loc == "на" then
args.loc = "на +"
else
args.loc = "в +,на +"
end
end
local arg_set = {}
table.insert(arg_set, stress)
table.insert(arg_set, stem)
table.insert(arg_set, decl)
local per_word_info = {{{arg_set}, ""}}
return generate_forms_1(args, per_word_info)
end
--------------------------------------------------------------------------
-- Autodetection and lemma munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the stem and the ending. GENDER must be present with -ь and plural
-- stems, and is otherwise ignored. Return up to three values: The stem
-- (lemma minus ending), the singular lemma ending, and if the lemma was
-- plural, the plural lemma ending. If the lemma was singular, the singular
-- lemma ending will contain any user-given accents; likewise, if the
-- lemma was plural, the plural ending will contain such accents.
-- VARIANT comes from the declension spec and controls certain declension
-- variants.
local function detect_lemma_type(lemma, tr, gender, args, variant)
local base, ending = rmatch(lemma, "^(.*)([еЕ]" .. AC .. ")$") -- accented
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([еЕ])$") -- unaccented
if base then
if variant == "-ище" and not rfind(lemma, "[щЩ][еЕ]$") then
error("With declension variant -ище, lemma should end in -ще: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), variant == "-ище" and "(ищ)е-и" or "о"
end
if variant == "-ишко" then
base, ending = rmatch(lemma, "^(.*[шШ][кК])([оО])$") -- unaccented
if not base then
error("With declension variant -ишко, lemma should end in -шко: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), "(ишк)о-и"
end
if variant == "-ин" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$") -- maybe accented
if not base then
error("With declension variant -ин, lemma should end in -ин(ъ): " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
-- Now autodetect -ин; only animate and in -анин/-янин
base, ending = rmatch(lemma, "^(.*[аАяЯ][" .. AC .. GR .. "]?[нН])([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$")
-- Need to check the animacy to avoid nouns like маиганин, цианин,
-- меланин, соланин, etc.
if base and args.thisa == "a" then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([мМ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
--recognize plural endings
if gender == "n" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
-- Don't do this; о/-ья is too rare
-- error("Ambiguous plural lemma " .. lemma .. " in -ья, singular could be -о or -ье/-ьё; specify the singular")
return base, com.strip_tr_ending(tr, ending), "ье", ending
end
base, ending = rmatch(lemma, "^(.*)([аяАЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), rfind(ending, "[аА]") and "о" or "е", ending
end
base, ending = rmatch(lemma, "^(.*)([ыиЫИ][" .. AC .. GR .. "]?)$")
if base then
if rfind(ending, "[ыЫ]") or rfind(base, "[" .. com.sib .. com.velar .. "]$") then
return base, com.strip_tr_ending(tr, ending), "о-и", ending
else
-- FIXME, should we return a slash declension?
error("No neuter declension е-и available; use a slash declension")
end
end
end
if gender == "f" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ья", ending
end
end
-- Recognize masculines with irregular plurals, but only if the user
-- either explicitly specified that this noun is plural (n=p) or
-- specifically requested the irregular plural. This is necessary
-- because some masculine nouns have feminine endings, which look
-- like irregular plurals.
if gender == "m" then
if args.thisn == "p" or variant == "-ья" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-ья" or "-ья"), ending
end
end
if args.thisn == "p" or args.want_sc1 then
base, ending = rmatch(lemma, "^(.*)([аА][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-а" or "-а"), ending
end
base, ending = rmatch(lemma, "^(.*)([яЯ][" .. AC .. GR .. "]?)$")
if base then
if rfind(base, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return base, com.strip_tr_ending(tr, ending), "й-я", ending
else
return base, com.strip_tr_ending(tr, ending), "ь-я", ending
end
end
end
end
if gender == "m" or gender == "f" then
base, ending = rmatch(lemma, "^(.*[" .. com.sib .. com.velar .. "])([иИ][" .. AC .. GR .. "]?)$")
if not base then
base, ending = rmatch(lemma, "^(.*)([ыЫ][" .. AC .. GR .. "]?)$")
end
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and (args.old and "ъ" or "") or "а", ending
end
base, ending = rmatch(lemma, "^(.*[" .. com.vowel .. "й][" .. AC .. GR .. "]?)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "й" or "я", ending
end
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "ь-m" or "я", ending
end
end
if gender == "3f" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ь-f", ending
end
end
-- end of recognize-plurals code
base, ending = rmatch(lemma, "^(.*)([ьЬ][яеёЯЕЁ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([йаяеоёъЙАЯЕОЁЪ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ьЬ])$")
if base then
if gender == "m" or gender == "f" then
return base, com.strip_tr_ending(tr, ending), "ь-" .. gender
elseif gender == "3f" then
return base, com.strip_tr_ending(tr, ending), "ь-f"
else
error("Need to specify gender m or f with lemma in -ь: ".. lemma)
end
end
if rfind(lemma, "[ыиЫИ][" .. AC .. GR .. "]?$") then
error("If this is a plural lemma, gender must be specified: " .. lemma)
elseif rfind(lemma, "[иИіІуУыЫѣѢэЭюЮѵѴ]" .. DIA .. "?[" .. AC .. GR .. "]?$") then
error("Don't know how to decline lemma ending in this type of vowel: " .. lemma)
end
return lemma, tr, ""
end
local plural_variant_detection_map = {
[""] = {["-ья"]="-ья"},
["ъ"] = {["-ья"]="ъ-ья"},
}
local special_case_1_to_plural_variant = {
[""] = "-а",
["ъ"] = "ъ-а",
["й"] = "й-я",
["ь-m"] = "ь-я",
["о"] = "о-и",
-- these last two are here to avoid getting errors in that checks for
-- compatibility with special case 1; the basic variants of these decls
-- don't actually exist
["(ишк)о"] = "(ишк)о-и",
["(ищ)е"] = "(ищ)е-и",
}
local function map_decl(decl, fun)
if rfind(decl, "/") then
local split_decl = rsplit(decl, "/")
if #split_decl ~= 2 then
error("Mixed declensional class " .. decl
.. "needs exactly two classes, singular and plural")
end
return fun(split_decl[1]) .. "/" .. fun(split_decl[2])
else
return fun(decl)
end
end
-- Canonicalize decl class into non-accented and alias-resolved form;
-- but note that some canonical decl class names with an accent in them
-- (e.g. е́, not the same as е, whose accented version is ё; and various
-- adjective declensions).
local function canonicalize_decl(decl, old)
local function do_canon(decl)
-- remove accents, but not from е́ (for adj decls, accent matters
-- as well but we handle that by mapping the accent to a stress pattern
-- and then to the accented version in determine_stress_variant())
if decl ~= "е́" then
decl = com.remove_accents(decl)
end
local decl_aliases = old and declensions_old_aliases or declensions_aliases
local decl_cats = old and declensions_old_cat or declensions_cat
if decl_aliases[decl] then
-- If we find an alias, map it.
decl = decl_aliases[decl]
elseif not decl_cats[decl] then
error("Unrecognized declension class " .. decl)
end
return decl
end
return map_decl(decl, do_canon)
end
-- Attempt to determine the actual declension (including plural variants)
-- based on a combination of the declension the user specified, what can be
-- detected from the lemma, and special case (1), if given in the declension.
-- DECL is the value the user passed for the declension field, after
-- extraneous annotations (special cases (1) and (2), * for reducible,
-- ё for ё/ё alternation and a ; that may precede ё) have been stripped off.
-- What's left is one of the following:
--
-- 1. Blank, meaning to autodetect the declension from the lemma
-- 2. A hyphen followed by a declension variant (-ья, -ин, -ишко, -ище; see
-- long comment at top of file)
-- 3. A gender (m, f, n, 3f)
-- 4. A gender plus declension variant (e.g. f-ья)
-- 5. An actual declension, possibly including a plural variant (e.g. о-и) or
-- a slash declension (e.g. я/-ья, used for the noun дядя).
--
-- Return seven args: stem (lemma minus ending), translit, canonicalized
-- declension, explicitly specified gender if any (m, f, n or nil), whether
-- the specified declension or detected ending was accented, whether the
-- detected ending was pl, and whether the declension was autodetected
-- (corresponds to cases where a full word with ending attached is required
-- in the lemma field). "Canonicalized" means after autodetection, with
-- accents removed, with any aliases mapped to their canonical versions
-- and with any requested declension variants applied. The result is either a
-- declension that will have a categorization entry (in declensions_cat[] or
-- declensions_old_cat[]) or a slash declension where each part similarly has
-- a categorization entry.
--
-- Note that gender is never required when an explicit declension is given,
-- and in connection with stem autodetection is required only when the lemma
-- either ends in -ь or is plural.
determine_decl = function(lemma, tr, decl, args)
-- Assume we're passed a value for DECL of types 1-4 above, and
-- fetch gender and requested declension variant.
local stem
local want_ya_plural, orig_pl_ending, variant
local was_autodetected
local gender = rmatch(decl, "^(3?[mfn]?)$")
if not gender then
gender, variant = rmatch(decl, "^(3?[mfn]?)(%-[^%-]+)$")
-- But be careful with explicit declensions like -а that look like
-- variants without gender (FIXME, eventually we should maybe do
-- something about the potential ambiguity).
if gender == "" and not m_table.contains({"-ья", "-ин", "-ишко", "-ище"}, variant) then
gender, variant = nil, nil
end
end
-- If DECL is of type 1-4, handle declension variants and detect
-- the actual declension from the lemma.
if gender then
-- Check for declension variants
if variant then
if variant == "-ья" then
want_ya_plural = "-ья"
else
-- Sanity-check remaining declension variants, which need
-- specific values of animacy, gender and special-case (1)
local sc1_needed
local animate_needed
if variant == "-ишко" then
animate_needed = false
sc1_needed = true
elseif variant == "-ище" then
animate_needed = true
sc1_needed = true
elseif variant == "-ин" then
animate_needed = true
sc1_needed = false
else
-- WARNING: If adding another variant, you need to also
-- add to the list farther above.
error("Unrecognized declension variant " .. variant .. ", should be -ья, -ин, -ишко or -ище")
end
if sc1_needed and not args.want_sc1 then
error("Declension variant " .. variant .. " must be used with special case (1)")
elseif sc1_needed == false and args.want_sc1 then
error("Declension variant " .. variant .. " must not be used with special case (1)")
end
if animate_needed and args.thisa ~= "a" then
error("Declension variant " .. variant .. " must be specified as animate")
elseif animate_needed == false and args.thisa == "a" then
error("Declension variant " .. variant .. " must not be specified as animate")
end
if gender ~= "" and gender ~= "m" then
error("Declension variant " .. variant .. " should be used with the masculine gender")
end
end
end
stem, tr, decl, orig_pl_ending = detect_lemma_type(lemma, tr, gender,
args, variant)
was_autodetected = true
else
stem, tr = lemma, tr
end
-- Now canonicalize gender
if gender == "3f" then
gender = "f"
elseif gender == "" then
gender = nil
end
-- The ending should be treated as accented if either the original singular
-- or plural ending was accented, or if the stem is non-syllabic.
local was_accented = com.is_stressed(decl) or
orig_pl_ending and com.is_stressed(orig_pl_ending) or
com.is_nonsyllabic(stem)
local was_plural = not not orig_pl_ending
decl = canonicalize_decl(decl, args.old)
-- The rest of this code concerns plural variants. It's somewhat
-- complicated because there are potentially four sources of plural
-- variants (not to mention plural variants constructed using slash
-- notation):
--
-- 1. A user-requested plural variant in declension types 2 or 4 above
-- (currently only -ья)
-- 2. An explicit plural variant encoded in an explicit declension of
-- type 5 above
-- 3. An autodetected plural variant (which will happen in some cases
-- when autodetection is performed on a nominative plural)
-- 4. A plural variant derived using special case (1).
--
-- Up to three actual plural variants might exist (e.g. if the user
-- specifies a DECL value or 'm-ья(1)' and a STEM ending in -а,
-- although not all three can ever be compatible because -ья and (1)
-- are never compatible). We can't have all four because if there's
-- an explicit plural variant, there won't be a user-requested or
-- autodetected plural variant.
--
-- The goal below is to do two things: Check that all available plural
-- variants are the same, and generate the actual declension.
-- If we have a type-2 or type-3 variant, we already have the actual
-- declension; else we need to use a table to map the basic declension
-- to the one with the plural variant encoded in it.
--
-- NOTE: The code below was written with a more general plural-variant
-- system. It probably can be simplified a lot now.
-- 1: Handle explicit decl with slash variant
if rfind(decl, "/") then
if want_ya_plural then
-- Don't think this can happen
error("Plural variant " .. want_ya_plural .. " not compatible with slash declension " .. decl)
end
if args.want_sc1 then
error("Special case (1) not compatible with slash declension" .. decl)
end
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- 2: Retrieve explicitly specified or autodetected decl and pl. variant
local basic_decl, detected_or_explicit_plural = rmatch(decl, "^(.*)(%-[^mf]+)$")
if basic_decl == "ь" then
basic_decl = "ь-m"
end
basic_decl = basic_decl or decl
-- 3: Any user-requested plural variant must agree with explicit or
-- autodetected variant.
if want_ya_plural and detected_or_explicit_plural and want_ya_plural ~= detected_or_explicit_plural then
error("Plural variant " .. want_ya_plural .. " requested but plural variant " .. detected_or_explicit_plural .. " detected from plural stem")
end
-- 4: Handle special case (1). Derive the full declension, make sure its
-- plural variant matches any other available plural variants, and
-- return the declension.
if args.want_sc1 then
local sc1_decl = special_case_1_to_plural_variant[basic_decl] or
error("Special case (1) not compatible with declension " .. basic_decl)
local sc1_plural = rsub(sc1_decl, "^.*%-", "-")
local other_plural = want_ya_plural or detected_or_explicit_plural
if other_plural and sc1_plural ~= other_plural then
error("Plural variant " .. other_plural .. " specified or detected, but special case (1) calls for plural variant " .. sc1_plural)
end
return stem, tr, sc1_decl, gender, was_accented, was_plural, was_autodetected
end
-- 5: Handle user-requested plural variant without explicit or detected
-- one. (If an explicit or detected one exists, we've already checked
-- that it agrees with the user-requested one, and so we already have
-- our full declension.)
if want_ya_plural and not detected_or_explicit_plural then
local variant_decl
if plural_variant_detection_map[decl] then
variant_decl = plural_variant_detection_map[decl][want_ya_plural]
end
if variant_decl then
return stem, tr, variant_decl, gender, was_accented, was_plural, was_autodetected
else
return stem, tr, decl .. (args.old and "/ъ-ья" or "/-ья"), gender, was_accented, was_plural, was_autodetected
end
end
-- 6: Just return the full declension, which will include any available
-- plural variant in it.
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- Convert soft adjectival declensions into hard ones following certain
-- stem-final consonants. FIXME: We call this in two places, once
-- to handle auto-detection and once to handle explicit declensions; but
-- in the former case we end up calling it twice.
local function determine_adj_stem_variant(decl, stem)
local iend = rmatch(decl, "^%+[іи]([йея]?)$")
-- Convert ій/ий to ый after velar or sibilant. This is important for
-- velars; doesn't really matter one way or the other for sibilants as
-- the sibilant rules will convert both sets of endings to the same
-- thing (whereas there will be a difference with о vs. е for velars).
if iend and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl = "+ы" .. iend
-- The following is necessary for -ц, unclear if makes sense for
-- sibilants. (Would be necessary -- I think -- if we were
-- inferring short adjective forms, but we're not.)
elseif decl == "+ее" and rfind(stem, "[" .. com.sib_c .. "]$") then
decl = "+ое"
end
return decl
end
-- Attempt to determine the actual adjective declension based on a
-- combination of the declension the user specified and what can be detected
-- from the stem. DECL is the value the user passed for the declension field,
-- after extraneous annotations have been removed (although none are probably
-- relevant here). What's left is one of the following, which always begins
-- with +:
--
-- 1. +, meaning to autodetect the declension from the stem
-- 2. +ь, same as + but selects +ьий instead of +ий if lemma ends in -ий
-- 3. +short, +mixed or +proper, with the declension partly specified but
-- the particular gender/number-specific short/mixed variant to be
-- autodetected
-- 4. A gender (+m, +f or +n), used only for detecting the singular of
-- plural-form lemmas (this is primarily used in conjunction with template
-- ru-noun+, to explicitly specify the gender; for the actual declension,
-- it doesn't much matter what singular gender we pick since we're a
-- plural only)
-- 5. A gender plus short/mixed/proper/ь (e.g. +f-mixed), again with the gender
-- used only for detecting the singular of plural-form short/mixed lemmas
-- 6. An actual declension, possibly including a slash declension
-- (WARNING: Unclear if slash declensions will work, especially those
-- that are adjective/noun combinations)
--
-- Returns the same seven args as for determine_decl(). The returned
-- declension will always begin with +.
detect_adj_type = function(lemma, tr, decl, old)
local was_autodetected
local base, ending
local basedecl, g = rmatch(decl, "^(%+)([mfn])$")
if not basedecl then
g, basedecl = rmatch(decl, "^%+([mfn])%-([a-zь]+)$")
if basedecl then
basedecl = "+" .. basedecl
end
end
decl = basedecl or decl
if decl == "+" or decl == "+ь" then
local loc = rfind(lemma, "[аеиіоыя][" .. AC .. GR .. "]?[йея]$") or rfind(lemma, "ь[йея]$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
end
if ending == "ий" and decl == "+ь" then
decl = "+ьий"
elseif ending == "ій" and decl == "+ь" then
decl = "+ьій"
elseif ending then
decl = "+" .. ending
else
local loc, shortmixed = rfind(lemma, "[аоы][" .. AC .. GR .. "]?$") or rfind(lemma, "ъ?$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
shortmixed = rfind(base, "^[" .. com.uppercase .. "].*[иы]" .. AC .. "н$") and "stressed-proper" or -- accented
rfind(base, "^[" .. com.uppercase .. "].*[иы]н$") and "proper" or --not accented
rlfind(base, "[ёео][" .. AC .. GR .. "]?в$") and "short" or
rlfind(base, "[ыи]" .. AC .. "н$") and "stressed-short" or -- accented
rlfind(base, "[ыи]н$") and "mixed" --not accented
end
if not shortmixed then
error("Cannot determine stem type of adjective: " .. lemma)
end
decl = "+" .. ending .. "-" .. shortmixed
end
was_autodetected = true
elseif m_table.contains({"+short", "+mixed", "+proper"}, decl) then
base, ending = rmatch(lemma, "^(.-)([оаыъ]?[" .. AC .. GR .. "]?)$")
assert(base)
local shortmixed = usub(decl, 2)
if rlfind(base, "[ыи]" .. AC .. "н$") then -- accented
if shortmixed == "short" then shortmixed = "stressed-short"
elseif shortmixed == "proper" then shortmixed = "stressed-proper"
end
end
decl = "+" .. ending .. "-" .. shortmixed
was_autodetected = true
else
base = lemma
end
if ending and ending ~= "" then
tr = com.strip_tr_ending(tr, ending)
end
-- Remove any accents from the declension, but not their presence.
-- We will convert was_accented into stress pattern b, and convert that
-- back to an accented version in determine_stress_variant(). This way
-- we end up with the stressed version whether the user placed an accent
-- in the ending or decl or specified stress pattern b.
-- FIXME, might not work in the presence of slash declensions
local was_accented = com.is_stressed(decl)
decl = com.remove_accents(decl)
decl = map_decl(decl, function(decl)
return determine_adj_stem_variant(decl, base)
end)
local singdecl
if decl == "+ые" then
singdecl = (g == "m" or not g) and (was_accented and "+ой" or "+ый") or not old and g == "f" and "+ая" or not old and g == "n" and "+ое"
elseif decl == "+ыя" and old then
singdecl = (g == "f" or not g) and "+ая" or g == "n" and "+ое"
elseif decl == "+ие" and not old then
singdecl = (g == "m" or not g) and "+ий" or g == "f" and "+яя" or g == "n" and "+ее"
elseif decl == "+іе" and old and (g == "m" or not g) then
singdecl = "+ій"
elseif decl == "+ія" and old then
singdecl = (g == "f" or not g) and "+яя" or g == "n" and "+ее"
elseif decl == "+ьи" then
singdecl = (g == "m" or not g) and (old and "+ьій" or "+ьий") or g == "f" and "+ья" or g == "n" and "+ье"
elseif rfind(decl, "^%+ы%-") then -- decl +ы-mixed or similar
local beg = (g == "m" or not g) and (old and "ъ" or "") or g == "f" and "а" or g == "n" and "о"
singdecl = beg and "+" .. beg .. usub(decl, 3)
end
if singdecl then
was_plural = true
decl = singdecl
end
return base, tr, canonicalize_decl(decl, old), g, was_accented, was_plural, was_autodetected
end
-- If stress pattern omitted, detect it based on whether ending is stressed
-- or the decl class or stem accent calls for inherent stress, defaulting to
-- pattern a. This is run after alias resolution and accent removal of DECL;
-- WAS_ACCENTED indicates whether the ending was originally stressed.
-- FIXME: This is run before splitting slash patterns but should be run after.
detect_stress_pattern = function(stem, decl, decl_cats, reducible,
was_plural, was_accented)
-- ёнок and ёночек always bear stress
if rfind(decl, "ёнокъ?") or rfind(decl, "ёночекъ?") then
return "b"
-- stressed suffix и́н; missing in plural and true endings don't bear stress
-- (except for exceptional господи́н)
elseif rfind(decl, "инъ?") and was_accented then
return "d"
-- Adjectival -ой always bears the stress
elseif rfind(decl, "%+ой") then
return "b"
-- Adjectival stressed-short, stressed-proper bears the stress
elseif rfind(decl, "^%+.*%-stressed") then
return "b"
-- Pattern b if ending was accented by user
elseif was_accented then
return "b"
-- Nonsyllabic stem means pattern b
elseif com.is_nonsyllabic(stem) then
return "b"
-- Accent on reducible vowel in masc nom sg (not plural) means pattern b.
-- Think about whether we want to enable this.
-- elseif reducible and not was_plural then
-- -- FIXME hack. Eliminate plural part of slash declension.
-- decl = rsub(decl, "/.*", "")
-- if decl_cats[decl] and decl_cats[decl].g == "m" then
-- if com.is_ending_stressed(stem) or com.is_monosyllabic(stem) then
-- return "b"
-- end
-- end
end
return "a"
end
-- In certain special cases, depending on the declension, we override the
-- user-specified stress pattern and convert it to something else.
-- NOTE: This function is run after alias resolution and accent removal.
-- FIXME: It's also run before splitting slash patterns but should be run after.
override_stress_pattern = function(decl, stress)
-- ёнок and ёночек always bear stress; if user specified a,
-- convert to b. Don't do this with slash patterns (see FIXME above).
if stress == "a" and (rfind(decl, "^ёнокъ?$") or rfind(decl, "^ёночекъ?$")) then
return "b"
end
return stress
end
-- Canonicalize an adjectival declension to either the stressed or unstressed
-- variant depending on the stress. Ultimately this is what ensures that
-- the user's stress mark on an adjectival ending is respected.
determine_stress_variant = function(decl, stress)
if stress == "b" then
if decl == "+ая" then
return "+а́я"
elseif decl == "+ое" then
return "+о́е"
else
-- Convert +...-short to +...-stressed-short and same for -proper
local b, e = rmatch(decl, "^%+(.*)%-(short)$")
if not b then
b, e = rmatch(decl, "^%+(.*)%-(proper)$")
end
if b and not rfind(b, "%-stressed") then
return "+" .. b .. "-stressed-" .. e
end
end
end
return decl
end
-- Canonicalize a declension based on the final stem consonant, in
-- particular converting soft declensions to hard ones after velars and/or
-- sibilants. FIXME: We also do this canonicalization earlier on during
-- auto-detection (determine_adj_stem_variant() is called by
-- detect_adj_type(), and code in detect_lemma_type() does the equivalent
-- of the first clause below). Doing it here ensures that explicitly
-- specified declensions get handled as well, but it would be nice to not
-- do the same thing twice in the auto-detection case.
determine_stem_variant = function(decl, stem)
if decl == "е" and rfind(stem, "[" .. com.sib_c .. "]$") then
return "о"
end
return determine_adj_stem_variant(decl, stem)
end
is_reducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "3rd" and decl_cat.g == "f" or decl_cat.g == "m" then
return true
else
return false
end
end
-- Reduce nom sg to stem by eliminating the "epenthetic" vowel. Applies to
-- masculine 2nd-declension hard and soft, and 3rd-declension feminine in
-- -ь. STEM and DECL are after determine_decl(), before converting
-- outward-facing declensions to inward ones.
function export.reduce_nom_sg_stem(stem, tr, decl, soft_n, can_err)
local full_stem = stem .. (decl == "й" and decl or "")
local full_tr = tr and tr .. (decl == "й" and "j" or "")
local ret, rettr = com.reduce_stem(full_stem, full_tr, soft_n)
if not ret and can_err then
error("Unable to reduce stem " .. stem)
end
return ret, rettr
end
is_dereducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "1st" or decl_cat.decl == "2nd" and decl_cat.g == "n" then
return true
else
return false
end
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. dereducible nouns
-- in -ня.
add_bare_suffix = function(bare, baretr, old, sgdc, dereduced)
if old and sgdc.hard == "hard" then
-- Final -ъ isn't transliterated
return bare .. "ъ", baretr
elseif sgdc.hard == "soft" or sgdc.hard == "palatal" then
-- This next clause corresponds to a special case in Vitalik's module.
-- It says that nouns in -ня (accent class a) have gen pl without
-- trailing -ь. It appears to apply to most nouns in -ня (possibly
-- all in -льня), but ку́хня (gen pl ку́хонь) and дерéвня (gen pl
-- дереве́нь) is an exception. (Vitalik's module has an extra
-- condition here 'stress == "a"' that would exclude дере́вня but I
-- don't think this condition is in Zaliznyak, as he indicates
-- дере́вня as having an exceptional genitive plural.)
if dereduced and rfind(bare, "[нН]$") and sgdc.decl == "1st" then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
-- Final -ъ isn't transliterated
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return bare .. "й", baretr and (baretr .. "j")
else
return bare .. "ь", baretr and (baretr .. "ʹ")
end
else
return bare, baretr
end
end
-- Dereduce stem to the form found in the gen pl (and maybe nom sg) by
-- inserting an epenthetic vowel. Applies to 1st declension and 2nd
-- declension neuter, and to 2nd declension masculine when the stem was
-- specified as a plural form (in which case we're deriving the nom sg,
-- and also the gen pl in the alt-gen-pl scenario). STEM and DECL are
-- after determine_decl(), before converting outward-facing declensions
-- to inward ones. STRESS is the stess pattern.
function export.dereduce_nom_sg_stem(stem, tr, sgdc, stress, old, can_err)
local epenthetic_stress = ending_stressed_gen_pl_patterns[stress]
local ret, rettr = com.dereduce_stem(stem, tr, epenthetic_stress)
if not ret then
if can_err then
error("Unable to dereduce stem " .. stem)
else
return nil, nil
end
end
return add_bare_suffix(ret, rettr, old, sgdc, true)
end
--------------------------------------------------------------------------
-- Second-declension masculine --
--------------------------------------------------------------------------
----------------- Masculine hard -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style).
declensions_old["ъ"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and "е́й" or "о́въ"
end,
["alt_gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["ъ"] = { decl="2nd", hard="hard", g="m" }
-- Normal mapping of old ъ would be "" (blank), but we set up "#" as an alias
-- so we have a way of referring to it without defaulting if need be and
-- distinct from auto-detection (e.g. in the second stem of a word, or to
-- override autodetection of -ёнок or -ин -- the latter is necessary in the
-- case of семьянин).
declensions_aliases["#"] = ""
----------------- Masculine hard, irregular plural -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg nom pl -а.
declensions_old["ъ-а"] = mw.clone(declensions_old["ъ"])
declensions_old["ъ-а"]["nom_pl"] = "а́"
declensions_old_cat["ъ-а"] = { decl="2nd", hard="hard", g="m", alt_nom_pl=true }
declensions_aliases["#-a"] = "-a"
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg soft pl -ья.
-- Differs from the normal declension throughout the plural.
declensions_old["ъ-ья"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = "ьёвъ",
["alt_gen_pl"] = "е́й",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ъ-ья"] = { decl="2nd", hard="hard", g="m", irregpl=true }
declensions_aliases["#-ья"] = "-ья"
----------------- Masculine hard, suffixed, irregular plural -------------------
declensions_old["инъ"] = {
["nom_sg"] = "и́нъ",
["gen_sg"] = "и́на",
["dat_sg"] = "и́ну",
["acc_sg"] = nil,
["ins_sg"] = "и́номъ",
["pre_sg"] = "и́нѣ",
["nom_pl"] = "е́",
["gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["инъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old["ёнокъ"] = {
["nom_sg"] = "ёнокъ",
["gen_sg"] = "ёнка",
["dat_sg"] = "ёнку",
["acc_sg"] = nil,
["ins_sg"] = "ёнкомъ",
["pre_sg"] = "ёнкѣ",
["nom_pl"] = "я́та",
["gen_pl"] = "я́тъ",
["dat_pl"] = "я́тамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тами",
["pre_pl"] = "я́тахъ",
}
declensions_old_cat["ёнокъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["онокъ"] = "ёнокъ"
declensions_old_aliases["енокъ"] = "ёнокъ"
declensions_old["ёночекъ"] = {
["nom_sg"] = "ёночекъ",
["gen_sg"] = "ёночка",
["dat_sg"] = "ёночку",
["acc_sg"] = nil,
["ins_sg"] = "ёночкомъ",
["pre_sg"] = "ёночкѣ",
["nom_pl"] = "я́тки",
["gen_pl"] = "я́токъ",
["dat_pl"] = "я́ткамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тками",
["pre_pl"] = "я́ткахъ",
}
declensions_old_cat["ёночекъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["оночекъ"] = "ёночекъ"
declensions_old_aliases["еночекъ"] = "ёночекъ"
----------------- Masculine soft -------------------
-- Normal soft-masculine declension in -ь
declensions_old["ь-m"] = {
["nom_sg"] = "ь",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["alt_gen_pl"] = "ь",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-m"] = { decl="2nd", hard="soft", g="m" }
-- Soft-masculine declension in -ь with irreg nom pl -я
declensions_old["ь-я"] = mw.clone(declensions_old["ь-m"])
declensions_old["ь-я"]["nom_pl"] = "я́"
declensions_old_cat["ь-я"] = { decl="2nd", hard="soft", g="m", alt_nom_pl=true }
----------------- Masculine palatal -------------------
-- Masculine declension in palatal -й
declensions_old["й"] = {
["nom_sg"] = "й",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = "ёвъ",
["alt_gen_pl"] = "й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["й"] = { decl="2nd", hard="palatal", g="m" }
declensions_old["й-я"] = mw.clone(declensions_old["й"])
declensions_old["й-я"]["nom_pl"] = "я́"
declensions_old_cat["й-я"] = { decl="2nd", hard="palatal", g="m", alt_nom_pl=true }
--------------------------------------------------------------------------
-- First-declension feminine --
--------------------------------------------------------------------------
----------------- Feminine hard -------------------
-- Hard-feminine declension in -а
declensions_old["а"] = {
["nom_sg"] = "а́",
["gen_sg"] = "ы́",
["dat_sg"] = "ѣ́",
["acc_sg"] = "у́",
["ins_sg"] = {"о́й<insa>", "о́ю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["а"] = { decl="1st", hard="hard", g="f" }
----------------- Feminine soft -------------------
-- Soft-feminine declension in -я
declensions_old["я"] = {
["nom_sg"] = "я́",
["gen_sg"] = "и́",
["dat_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_dat_sg_patterns[stress] and "и" or "ѣ́"
end,
["acc_sg"] = "ю́",
["ins_sg"] = {"ёй<insa>", "ёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "]́?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["я"] = { decl="1st", hard="soft", g="f" }
-- Soft-feminine declension in -ья.
-- Almost like ь + -я endings except for genitive plural.
declensions_old["ья"] = {
["nom_sg"] = "ья́",
["gen_sg"] = "ьи́",
["dat_sg"] = "ьѣ́",
["acc_sg"] = "ью́",
["ins_sg"] = {"ьёй<insa>", "ьёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ьи́",
["gen_pl"] = function(stem, stress)
-- circumflex accent is a signal that forces stress, particularly
-- in accent pattern d/d'.
return (ending_stressed_gen_pl_patterns[stress] or stress == "d" or stress == "d'") and "е̂й" or "ий"
end,
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ья"] = {
decl="1st", hard="soft", g="f",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
--------------------------------------------------------------------------
-- Second-declension neuter --
--------------------------------------------------------------------------
----------------- Neuter hard -------------------
-- Normal hard-neuter declension in -о
declensions_old["о"] = {
["nom_sg"] = "о́",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "о́" or nil
end,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "а́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "о́въ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["о"] = { decl="2nd", hard="hard", g="n" }
-- Hard-neuter declension in -о with irreg nom pl -и
declensions_old["о-и"] = mw.clone(declensions_old["о"])
declensions_old["о-и"]["nom_pl"] = "ы́"
declensions_old_cat["о-и"] = { decl="2nd", hard="hard", g="n", alt_nom_pl=true }
declensions_old_aliases["о-ы"] = "о-и"
-- Masculine-gender neuter-form declension in -(ишк)о with irreg nom pl -и,
-- with colloquial feminine endings in some of the singular cases
-- (§5 p. 74 of Zaliznyak)
declensions_old["(ишк)о-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ишк)о-и"]["gen_sg"] = {"а́", "ы́1"}
declensions_old["(ишк)о-и"]["dat_sg"] = {"у́", "ѣ́1"}
declensions_old["(ишк)о-и"]["ins_sg"] = {"о́мъ", "о́й1"}
declensions_old_cat["(ишк)о-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ишк)о-и"] = "<sup>1</sup> Colloquial."
-- Masculine-gender animate neuter-form declension in -(ищ)е with irreg
-- nom pl -и, with colloquial feminine endings in some of the singular cases
-- (§4 p. 74 of Zaliznyak)
declensions_old["(ищ)е-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ищ)е-и"]["acc_sg"] = {"а́", "у́1"}
declensions_old["(ищ)е-и"]["gen_sg"] = {"а́", "ы́2"}
declensions_old["(ищ)е-и"]["dat_sg"] = {"у́", "ѣ́2"}
declensions_old["(ищ)е-и"]["ins_sg"] = {"о́мъ", "о́й2"}
declensions_old_cat["(ищ)е-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ищ)е-и"] = "<sup>1</sup> Colloquial.<br /><sup>2</sup> Less common, more colloquial."
----------------- Neuter soft -------------------
-- Soft-neuter declension in -е (stressed -ё)
declensions_old["е"] = {
["nom_sg"] = "ё",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ё" or nil
end,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е"] = {
singular = function(suffix)
if suffix == "ё" then
return "ending in -ё"
else
return {}
end
end,
decl="2nd", hard="soft", g="n", gensg=true
}
-- User-facing declension type "ё" = "е"
declensions_old_aliases["ё"] = "е"
-- Rare soft-neuter declension in stressed -е́ (e.g. муде́, бытие́)
declensions_old["е́"] = {
["nom_sg"] = "е́",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "е́" or nil
end,
["ins_sg"] = "е́мъ",
["pre_sg"] = function(stem, stress)
-- FIXME!!! Are we sure about this condition? This is what was
-- found in the old template, but the related -е declension has
-- -ие prep sg ending -(и)и only when *not* stressed.
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and "и́" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "й" or "е́й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е́"] = {
singular = "ending in stressed -е",
decl="2nd", hard="soft", g="n", gensg=true
}
-- Soft-neuter declension in unstressed -ье (stressed -ьё).
declensions_old["ье"] = {
["nom_sg"] = "ьё",
["gen_sg"] = "ья́",
["dat_sg"] = "ью́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ьё" or nil
end,
["ins_sg"] = "ьёмъ",
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and "е́й" or "ий"
end,
["alt_gen_pl"] = "ьёвъ",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ье"] = {
decl="2nd", hard="soft", g="n",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
declensions_old_aliases["ьё"] = "ье"
--------------------------------------------------------------------------
-- Third declension --
--------------------------------------------------------------------------
declensions_old["ь-f"] = {
["nom_sg"] = "ь",
["gen_sg"] = "и́",
["dat_sg"] = "и́",
["acc_sg"] = "ь",
["ins_sg"] = "ью́",
["pre_sg"] = "и́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-f"] = { decl="3rd", hard="soft", g="f" }
declensions_old["мя"] = {
["nom_sg"] = "мя",
["gen_sg"] = "мени",
["dat_sg"] = "мени",
["acc_sg"] = nil,
["ins_sg"] = "менемъ",
["pre_sg"] = "мени",
["nom_pl"] = "мена́",
["gen_pl"] = "мёнъ",
["dat_pl"] = "мена́мъ",
["acc_pl"] = nil,
["ins_pl"] = "мена́ми",
["pre_pl"] = "мена́хъ",
}
declensions_old_cat["мя"] = { decl="3rd", hard="soft", g="n", cant_reduce=true }
--------------------------------------------------------------------------
-- Indeclinable --
--------------------------------------------------------------------------
-- Indeclinable declension; no endings.
declensions_old["$"] = {
["nom_sg"] = "",
["gen_sg"] = "",
["dat_sg"] = "",
["acc_sg"] = nil,
["ins_sg"] = "",
["pre_sg"] = "",
["nom_pl"] = "",
["gen_pl"] = "",
["dat_pl"] = "",
["acc_pl"] = nil,
["ins_pl"] = "",
["pre_pl"] = "",
}
declensions_old_cat["$"] = { decl="indeclinable", hard="none", g="none" }
--------------------------------------------------------------------------
-- Adjectival --
--------------------------------------------------------------------------
-- This needs to be up here because it is called just below.
local function old_to_new(v)
v = rsub(v, "ъ$", "")
v = rsub(v, "^ъ", "")
v = rsub(v, "(%A)ъ", "%1")
v = rsub(v, "ъ(%A)", "%1")
v = rsub(v, "і", "и")
v = rsub(v, "ѣ", "е")
return v
end
-- Meaning of entry is:
-- 1. The declension name in module ru-adjective
-- 2. The masculine declension name in this module
-- 3. The neuter declension name in this module
-- 4. The feminine declension name in this module
-- 5. The value of hard= for the declensions_cat entry
-- 6. The value of decl= for the declensions_cat entry
-- 7. The value of possadj= for the declensions_cat entry (true if possessive
-- or similar type of adjective)
local adj_decl_map = {
{"ый", "ый", "ое", "ая", "hard", "long", false},
{"ій", "ій", "ее", "яя", "soft", "long", false},
{"ой", "ой", "о́е", "а́я", "hard", "long", false},
{"ьій", "ьій", "ье", "ья", "palatal", "long", true},
{"short", "ъ-short", "о-short", "а-short", "hard", "short", true},
{"mixed", "ъ-mixed", "о-mixed", "а-mixed", "hard", "mixed", true},
{"proper", "ъ-proper", "о-proper", "а-proper", "hard", "proper", true},
{"stressed-short", "ъ-stressed-short", "о-stressed-short", "а-stressed-short", "hard", "short", true},
{"stressed-proper", "ъ-stressed-proper", "о-stressed-proper", "а-stressed-proper", "hard", "proper", true},
}
local function get_adjectival_decl(adjtype, gender, old)
local decl, intnotes = m_ru_adj.get_nominal_decl(adjtype, gender, old)
-- hack fem ins_sg to insert <insa>, <insb>; see concat_word_forms_1()
if gender == "f" and type(decl["ins_sg"]) == "table" and #decl["ins_sg"] == 2 then
decl["ins_sg"][1] = decl["ins_sg"][1] .. "<insa>"
decl["ins_sg"][2] = decl["ins_sg"][2] .. "<insb>"
end
return decl, intnotes
end
for _, declspec in ipairs(adj_decl_map) do
local oadjdecl = declspec[1]
local nadjdecl = old_to_new(oadjdecl)
local odecl_by_gender =
{m="+" .. declspec[2], n="+" .. declspec[3], f="+" .. declspec[4]}
local hard = declspec[5]
local decltype = declspec[6]
local possadj = declspec[7]
for _, g in ipairs({"m", "n", "f"}) do
local odecl = odecl_by_gender[g]
local ndecl = old_to_new(odecl)
declensions_old[odecl], internal_notes_table_old[odecl] =
get_adjectival_decl(oadjdecl, g, true)
declensions[ndecl], internal_notes_table[ndecl] =
get_adjectival_decl(nadjdecl, g, false)
declensions_old_cat[odecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
declensions_cat[ndecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
end
end
-- Set up some aliases.
declensions_old_aliases["+о́-short"] = "+о-stressed-short"
declensions_old_aliases["+а́-short"] = "+а-stressed-short"
declensions_old_aliases["+о́-proper"] = "+о-stressed-proper"
declensions_old_aliases["+а́-proper"] = "+а-stressed-proper"
declensions_aliases["+#-short"] = "+-short"
declensions_aliases["+#-mixed"] = "+-mixed"
declensions_aliases["+#-proper"] = "+-proper"
declensions_aliases["+#-stressed-short"] = "+-stressed-short"
declensions_aliases["+#-stressed-proper"] = "+-stressed-proper"
--------------------------------------------------------------------------
-- Populate new from old --
--------------------------------------------------------------------------
-- Function to convert an entry in an old declensions table to new.
local function old_decl_entry_to_new(v)
if not v then
return nil
elseif type(v) == "table" then
local new_entry = {}
for _, i in ipairs(v) do
table.insert(new_entry, old_decl_entry_to_new(i))
end
return new_entry
elseif type(v) == "function" then
return function(stem, suffix, args)
return old_decl_entry_to_new(v(stem, suffix, args))
end
else
return old_to_new(v)
end
end
-- Function to convert an old declensions table to new.
local function old_decl_to_new(odecl)
local ndecl = {}
for k, v in pairs(odecl) do
ndecl[k] = old_decl_entry_to_new(v)
end
return ndecl
end
-- Function to convert an entry in an old declensions_cat table to new.
local function old_decl_cat_entry_to_new(odecl_cat_entry)
if not odecl_cat_entry then
return nil
elseif type(odecl_cat_entry) == "function" then
return function(suffix)
return old_decl_cat_entry_to_new(odecl_cat_entry(suffix))
end
elseif type(odecl_cat_entry) == "table" then
local ndecl_cat_entry = {}
for k, v in pairs(odecl_cat_entry) do
ndecl_cat_entry[k] = old_decl_cat_entry_to_new(v)
end
return ndecl_cat_entry
elseif type(odecl_cat_entry) == "boolean" then
return odecl_cat_entry
else
assert(type(odecl_cat_entry) == "string")
return old_to_new(odecl_cat_entry)
end
end
-- Function to convert an old declensions_cat table to new.
local function old_decl_cat_to_new(odeclcat)
local ndeclcat = {}
for k, v in pairs(odeclcat) do
ndeclcat[k] = old_decl_cat_entry_to_new(v)
end
return ndeclcat
end
-- populate declensions[] from declensions_old[]
for odecltype, odecl in pairs(declensions_old) do
local ndecltype = old_to_new(odecltype)
if not declensions[ndecltype] then
declensions[ndecltype] = old_decl_to_new(odecl)
end
end
-- populate declensions_cat[] from declensions_old_cat[]
for odecltype, odeclcat in pairs(declensions_old_cat) do
local ndecltype = old_to_new(odecltype)
if not declensions_cat[ndecltype] then
declensions_cat[ndecltype] = old_decl_cat_to_new(odeclcat)
end
end
-- populate declensions_aliases[] from declensions_old_aliases[]
for ofrom, oto in pairs(declensions_old_aliases) do
local from = old_to_new(ofrom)
if not declensions_aliases[from] then
declensions_aliases[from] = old_to_new(oto)
end
end
-- populate internal_notes_table[] from internal_notes_table_old[]
for odecl, note in pairs(internal_notes_table_old) do
local ndecl = old_to_new(odecl)
if not internal_notes_table[ndecl] then
-- FIXME, should we be calling old_to_new() here?
internal_notes_table[ndecl] = note
end
end
--------------------------------------------------------------------------
-- Inflection functions --
--------------------------------------------------------------------------
-- Attach the stressed stem (or plural stem, or barestem) out of ARGS
-- to the unstressed suffix SUF, modifying the suffix as necessary for the
-- last letter of the stem (e.g. if it is velar, sibilant or ц). CASE is
-- the case form being created and is used to select the plural stem if
-- needed. Returns two values, the combined form and the modified suffix.
local function attach_unstressed(args, case, suf, was_stressed)
if suf == nil then
return nil, nil
elseif rfind(suf, CFLEX) then -- if suf has circumflex accent, it forces stressed
return attach_stressed(args, case, suf)
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.pl, args.pltr
end
if not stem and case == "ins_sg" then
stem, tr = args.ins_sg_stem, args.ins_sg_tr
end
if not stem then
stem, tr = args.stem, args.stemtr
end
if nom.nonsyllabic_suffixes[suf] then
-- If gen_pl, use special args.gen_pl_bare if given, else regular
-- args.bare if there isn't a plural stem. If nom_sg, always use
-- regular args.bare.
local barearg, bareargtr
if case == "gen_pl" then
barearg, bareargtr = args.gen_pl_bare, args.gen_pl_baretr
if not barearg and args.pl == args.stem then
barearg, bareargtr = args.bare, args.baretr
end
else
barearg, bareargtr = args.bare, args.baretr
end
local barestem = barearg or stem
local barestem, baretr
if barearg then
barestem, baretr = barearg, bareargtr
else
barestem, baretr = stem, tr
end
if was_stressed and case == "gen_pl" then
if not barearg then
local gen_pl_stem, gen_pl_tr = com.make_ending_stressed(stem, tr)
barestem, baretr = gen_pl_stem, gen_pl_tr
end
end
if rlfind(barestem, "[йьъ]$") then
suf = ""
else
if suf == "ъ" then
-- OK
elseif suf == "й" or suf == "ь" then
if barearg and case == "gen_pl" then
-- explicit bare or reducible, don't add -ь
suf = ""
elseif rfind(barestem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
-- not reducible, do add -ь and correct to -й if necessary
suf = "й"
else
suf = "ь"
end
end
end
return com.concat_russian_tr(barestem, baretr, suf, nil, "dopair"), suf
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Analogous to attach_unstressed() but for the unstressed stem and a
-- stressed suffix.
attach_stressed = function(args, case, suf)
if suf == nil then
return nil, nil
end
-- circumflex forces stress even when the accent pattern calls for no stress
suf = rsub(suf, "̂", AC)
if com.is_unstressed(suf) then
return attach_unstressed(args, case, suf, "was stressed")
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.upl, args.upltr
end
if not stem then
stem, tr = args.ustem, args.ustemtr
end
local rules = nom.stressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Attach the appropriate stressed or unstressed stem (or plural stem as
-- determined by CASE, or barestem) out of ARGS to the suffix SUF, which may
-- be a list of alternative suffixes (e.g. in the inst sg of feminine nouns).
-- Calls FUN (either attach_stressed() or attach_unstressed()) to do the work
-- for an individual suffix. Returns two values, a list of combined forms
-- and a list of the real suffixes used (which may be modified from the
-- passed-in suffixes, e.g. by removing stress marks or modifying vowels in
-- various ways after a stem-final velar, sibilant or ц). Each combined form
-- is a two-element list {stem, tr} (or a one-element list if tr is nil).
-- IRREG is true if this is an irregular form. We are handling the Nth word;
-- ISLAST is true if this is the last one.
local function attach_with(args, case, suf, fun, irreg, n, islast)
if type(suf) == "table" then
local all_combineds = {}
local all_realsufs = {}
for _, x in ipairs(suf) do
local combineds, realsufs =
attach_with(args, case, x, fun, irreg, n, islast)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
for _, realsuf in ipairs(realsufs) do
table.insert(all_realsufs, realsuf)
end
end
return all_combineds, all_realsufs
else
local combined, realsuf = fun(args, case, suf)
local irregsuf = irreg and {IRREGMARKER} or {""}
return {combined and com.concat_paired_russian_tr(
com.concat_paired_russian_tr(args["prefix" .. n], combined),
com.concat_paired_russian_tr(args["suffix" .. n], irregsuf)) or nil},
{realsuf and realsuf .. args["suffix" .. n][1] or nil}
end
end
-- Generate the form(s) and suffix(es) for CASE according to the declension
-- table DECL, using the attachment function FUN (one of attach_stressed()
-- or attach_unstressed()). IS_SLASH is true if this is a slash declension
-- (different declensions for singular and plural). We are handling the Nth
-- word; ISLAST is true if this is the last one.
local function gen_form(args, decl, case, stress, fun, is_slash, n, islast)
local irreg = false
if not args.suffixes[case] then
args.suffixes[case] = {}
end
local decl_sufs = args.old and declensions_old or declensions
decl_sufs = decl_sufs[decl]
local suf = decl_sufs[case]
local decl_cats = args.old and declensions_old_cat or declensions_cat
local ispl = rfind(case, "_pl")
if ispl and (decl_cats[decl].irregpl or args.pl and args.pl ~= args.stem or is_slash) then
irreg = true
end
if case == "nom_pl" and decl_cats[decl].alt_nom_pl then
irreg = true
end
if type(suf) == "function" then
suf = suf(ispl and args.pl or args.stem, stress, args)
end
if case == "gen_pl" and args.alt_gen_pl then
suf = decl_sufs.alt_gen_pl
irreg = true
if not suf then
error("No alternative genitive plural available for this declension class")
end
end
local combineds, realsufs = attach_with(args, case, suf, fun, irreg, n, islast)
for _, realsuf in ipairs(realsufs) do
args.any_non_nil[case] = true
args.this_any_non_nil[case] = true
insert_if_not(args.suffixes[case], realsuf)
end
return combineds
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
}
do_stress_pattern = function(stress, args, decl, number, n, islast)
local f = {}
for _, case in ipairs(decl_cases) do
if not number or (number == "sg" and rfind(case, "_sg")) or
(number == "pl" and rfind(case, "_pl")) then
f[case] = gen_form(args, decl, case, stress,
attachers[stress_patterns[stress][case]], not not number,
n, islast)
-- Turn empty form lists into nil to facilitate computation of
-- animate/inanimate accusatives below
if f[case] and #f[case] == 0 then
f[case] = nil
end
-- Compute linked versions of potential lemma cases, for use
-- in the ru-noun+ headword. We substitute the original lemma
-- (before removing links) for forms that are the same as the
-- lemma, if the original lemma has links.
if f[case] and (case == "nom_sg" or case == "nom_pl") then
local linked_forms = {}
for _, form in ipairs(f[case]) do
-- Return true if FORM is "close enough" to LEMMA that we can substitute the
-- linked form of the lemma. Currently this means exactly the same except that
-- we ignore acute and grave accent differences in monosyllables, and ignore
-- notes that may have been appended (e.g. the triangle marking irregularity).
local entry, notes = m_table_tools.separate_notes(form[1])
local lemma = args.lemma_no_links
local close_enough_to_lemma =
entry == lemma or (com.is_monosyllabic(entry) and
com.is_monosyllabic(lemma) and
com.remove_accents(entry) == com.remove_accents(lemma))
if close_enough_to_lemma and
rfind(args.orig_lemma, "%[%[") then
table.insert(linked_forms, {args.orig_lemma .. notes, args.lemmatr and args.lemmatr .. notes})
else
table.insert(linked_forms, form)
end
end
f[case .. "_linked"] = linked_forms
end
end
end
-- Set acc an/in variants now as appropriate. We used to do this in
-- handle_forms_and_overrides(), which simplified the handling of
-- nom/gen/acc overrides but caused problems for words like мазло and
-- трепло that had a mixture of nil and non-nil accusative forms.
local an = args.thisa
if not number or number == "sg" then
f.acc_sg_an = f.acc_sg_an or f.acc_sg or an == "i" and f.nom_sg or f.gen_sg
f.acc_sg_in = f.acc_sg_in or f.acc_sg or an == "a" and f.gen_sg or f.nom_sg
end
if not number or number == "pl" then
f.acc_pl_an = f.acc_pl_an or f.acc_pl or an == "i" and f.nom_pl or f.gen_pl
f.acc_pl_in = f.acc_pl_in or f.acc_pl or an == "a" and f.gen_pl or f.nom_pl
end
for case, forms in pairs(f) do
if not args.forms[case] then
args.forms[case] = {}
end
for _, form in ipairs(forms) do
insert_if_not(args.forms[case], form)
end
end
end
stress_patterns["a"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["b"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["b'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["c"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["d"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["d'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["e"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f''"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
ending_stressed_gen_pl_patterns = m_table.listToSet({"b", "b'", "c", "e", "f", "f'", "f''"})
ending_stressed_pre_sg_patterns = m_table.listToSet({"b", "b'", "d", "d'", "f", "f'", "f''"})
ending_stressed_dat_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_pl_patterns = m_table.listToSet({"b", "b'", "c"})
local numbers = {
["s"] = "singular",
["p"] = "plural",
}
local old_title_temp = [=[မလဟုတ်စှ်ေကၠာပြုပြေၚ်ပြံၚ်လှာဲဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local extra_case_template, extra_case_template_with_plural
local internal_notes_template
local notes_template
local templates = {}
-- Convert a raw override into a canonicalized list of individual overrides.
-- If input is nil, so is output. Certain junk (e.g. <br/>) is removed,
-- and ~ and ~~ are substituted appropriately; ARGS and CASE are required for
-- this purpose. FORMS is the list of existing case forms and is currently
-- used only to retrieve the dat_sg for handling + in loc/par (this means
-- that any overrides of the dat_sg have to be handled before handling
-- overrides of loc/par). N is the suffix used to retrieve the override --
-- either a number for word-specific overrides, or an empty string for
-- overall overrides.
--
-- It will still be necessary to call m_table_tools.separate_notes() to separate
-- off any trailing "notes" (asterisks, superscript numbers, etc.), and
-- m_links.remove_links() to remove any links to get the raw override form.
canonicalize_override = function(args, case, forms, n)
local val = args[case .. n]
if not val then
return nil
end
-- clean <br /> that's in many multi-form entries and messes up linking
val = rsub(val, "<br%s*/>", "")
-- substitute ~ and ~~ and split by commas
local stem, manualtr
if rfind(case, "_pl") then
stem, manualtr = args.pl, args.pltr
end
if not stem then
stem, manualtr = args.stem, args.stemtr
end
local ustem, umanualtr = com.make_unstressed_once(stem, manualtr)
local stemtr, ustemtr = manualtr, umanualtr
local vals = rsplit(val, "%s*,%s*")
local retvals = {}
for _, val in ipairs(vals) do
local valru, valtr = com.split_russian_tr(val)
valru = rsub(valru, "~~", ustem)
valru = rsub(valru, "~", com.is_stressed(val) and ustem or stem)
if rfind(valru, "^%*") then
valru = rsub(valru, "^%*", "") .. HYPMARKER
end
if valtr then
stemtr = stemtr or com.translit_no_links(stem)
ustemtr = ustemtr or com.translit_no_links(ustem)
valtr = rsub(valtr, "~~", ustemtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and ustemtr or stemtr)
elseif val:find("~") and manualtr then
valtr = com.translit_no_links(val)
valtr = rsub(valtr, "~~", umanualtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and umanualtr or manualtr)
end
if valtr then
if valtr:sub(1, 1) == "*" then
valtr = valtr:sub(2) .. HYPMARKER
end
valtr = com.j_correction(valtr)
end
table.insert(retvals, {valru, valtr})
end
vals = retvals
-- handle + in loc/par meaning "the expected form"; NOTE: This requires
-- that dat_sg has already been processed!
if case == "loc" or case == "par" then
local new_vals = {}
for _, rutr in ipairs(vals) do
-- don't just handle + by itself in case the arg has в or на
-- or whatever attached to it
if rfind(rutr[1], "^%+") or rfind(rutr[1], "[%s%[|]%+") then
for _, dat in ipairs(forms["dat_sg"]) do
local ru, tr = rutr[1], rutr[2]
local datru, dattr = dat[1], dat[2]
local valru, valtr
-- separate off any footnote symbols (which may have been
-- introduced by a *tail or *tailall argument, which we need
-- to process before this stage so overrides don't get
-- automatically marked with footnote symbols); if par,
-- try to preserve them, but with loc this can cause
-- problems in case there are multiple dative forms
-- (stress variants) and the last one is marked with a
-- footnote symbol (occurs in грудь)
local datru_entry, datru_notes = m_table_tools.separate_notes(datru)
local dattr_entry, dattr_notes
if dattr then
dattr_entry, dattr_notes = m_table_tools.separate_notes(dattr)
end
if case == "par" then
valru, valtr = datru_entry, dattr_entry
else
valru, valtr = com.make_ending_stressed(datru_entry, dattr_entry)
datru_notes = ""
dattr_notes = ""
end
-- wrap the word in brackets so it's linked; but not if it
-- appears to already be linked
ru = rsub(ru, "^%+", "[[" .. valru .. "]]")
ru = rsub(ru, "([%[|])%+", "%1" .. valru)
ru = rsub(ru, "(%s)%+", "%1[[" .. valru .. "]]")
ru = ru .. datru_notes
-- do the translit; but it shouldn't have brackets in it
if tr or valtr then
tr = tr or com.translit_no_links(rutr[1])
valtr = valtr or com.translit_no_links(valru)
tr = rsub(tr, "^%+", valtr)
tr = rsub(tr, "(%s)%+", "%1" .. valtr)
tr = tr .. dattr_notes
end
table.insert(new_vals, {ru, tr})
end
else
table.insert(new_vals, rutr)
end
end
vals = new_vals
end
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(vals) do
local ru, tr = v[1], v[2]
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. n .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
vals = newvals
return vals
end
local function process_overrides(args, f, n)
local function process_override(case)
if args[case .. n] then
local overrides = canonicalize_override(args, case, f, n)
if not f[case] then
f[case] = {}
end
local new_overrides = {}
for _, form in ipairs(overrides) do
-- Don't consider overrides of loc/par/voc irregular since
-- they're only specified through overrides; FIXME: Theoretically
-- we could consider loc/par irregular if they don't follow the
-- expected forms; but we'd have to figure out how to eliminate
-- the preposition that may be specified
if not overridable_only_cases_set[case] and
not args.manual and
not contains_rutr_pair(f[case], form) then
local formru, formnotes = m_table_tools.separate_notes(form[1])
if formru ~= "-" then
-- don't mark an override of - as irregular, even if
-- it has an attached footnote symbol
form = com.concat_paired_russian_tr(form, {IRREGMARKER})
end
end
if case == "pauc" then
-- Internal note indicating that the form is for numbers 2, 3 and 4.
form = com.concat_paired_russian_tr(form, {paucal_marker})
end
table.insert(new_overrides, form)
end
f[case] = new_overrides
args.any_overridden[case] = true
end
end
-- do dative singular first because it will be used by loc/par
process_override("dat_sg")
-- now do the rest
for _, case in ipairs(overridable_cases) do
if case ~= "dat_sg" then
process_override(case)
end
end
-- if the nominative is overridden, use it to set the linked version unless
-- that is also specifically overridden
if args["nom_sg" .. n] and not args["nom_sg_linked" .. n] then
f.nom_sg_linked = f.nom_sg
end
if args["nom_pl" .. n] and not args["nom_pl_linked" .. n] then
f.nom_pl_linked = f.nom_pl
end
-- convert empty lists to nil to facilitate computation of accusative
-- case variants below.
for _, case in ipairs(all_cases) do
if f[case] then
if type(f[case]) ~= "table" then
error("Logic error, args[case] should be nil or table")
end
if #f[case] == 0 then
f[case] = nil
end
end
end
end
local function process_tail_args(args, f, n)
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function handle_tail_hyp(suf)
local arg, val
for _, case in ipairs(all_cases) do
arg = args[case .. "_" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args[case .. "_" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
if not rfind(case, "_pl") then
arg = args["sg" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["sg" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
else
arg = args["pl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["pl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
if not rfind(case, "nom_") and not rfind(case, "acc_") then
arg = args["obl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["obl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
end
end
handle_tail_hyp("tail")
handle_tail_hyp("hyp")
end
handle_forms_and_overrides = function(args, n, islast)
local f = args.forms
process_tail_args(args, f, n)
process_overrides(args, f, n)
local an = args.thisa
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). This logic duplicates logic in handle_overall_forms_and_overrides();
-- see long comment there. We need to duplicate the whole logic here to
-- handle words like мать-одиночка, which has an override of acc_sg1.
if not args["acc_sg_an" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_an = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_an = f.acc_sg or an == "i" and f.nom_sg or f.gen_sg or f.acc_sg_an
end
end
if not args["acc_sg_in" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_in = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_in = f.acc_sg or an == "a" and f.gen_sg or f.nom_sg or f.acc_sg_in
end
end
if not args["acc_pl_an" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_an = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_an = f.acc_pl or an== "i" and f.nom_pl or f.gen_pl or f.acc_pl_an
end
end
if not args["acc_pl_in" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_in = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_in = f.acc_pl or an == "a" and f.gen_pl or f.nom_pl or f.acc_pl_in
end
end
f.loc = f.loc or f.pre_sg
f.par = f.par or f.gen_sg
f.voc = f.voc or f.nom_sg
-- Set these in case we have plural only, in which case the
-- singular will also get set to these same values in case we are
-- a plural-only word in a singular-only expression.
f.loc_pl = f.loc_pl or f.pre_pl
f.par_pl = f.par_pl or f.gen_pl
f.voc_pl = f.voc_pl or f.nom_pl
f.count = f.count or f.gen_pl
f.pauc = f.pauc or f.gen_sg
local nu = args.thisn
-- If we have a singular-only, set the plural forms to the singular forms,
-- and vice-versa. This is important so that things work in multi-word
-- expressions that combine different number restrictions (e.g.
-- singular-only with singular/plural or singular-only with plural-only,
-- compare "St. Vincent and the Grenadines" [Сент-Винсент и Гренадины]).
if nu == "s" then
f.nom_pl_linked = f.nom_sg_linked
f.nom_pl = f.nom_sg
f.gen_pl = f.gen_sg
f.dat_pl = f.dat_sg
f.acc_pl = f.acc_sg
f.acc_pl_an = f.acc_sg_an
f.acc_pl_in = f.acc_sg_in
f.ins_pl = f.ins_sg
f.pre_pl = f.pre_sg
f.nom_pl = f.nom_sg
f.loc_pl = f.loc
f.par_pl = f.par
f.voc_pl = f.voc
elseif nu == "p" then
f.nom_sg_linked = f.nom_pl_linked
f.nom_sg = f.nom_pl
f.gen_sg = f.gen_pl
f.dat_sg = f.dat_pl
f.acc_sg = f.acc_pl
f.acc_sg_an = f.acc_pl_an
f.acc_sg_in = f.acc_pl_in
f.ins_sg = f.ins_pl
f.pre_sg = f.pre_pl
f.nom_sg = f.nom_pl
f.loc = f.loc_pl
f.par = f.par_pl
f.voc = f.voc_pl
end
end
handle_overall_forms_and_overrides = function(args)
local overall_forms = {}
for _, case in ipairs(displayable_cases) do
overall_forms[case] = concat_word_forms(args.per_word_info, case)
end
local acc_sg_overridden = args.acc_sg
local acc_pl_overridden = args.acc_pl
process_tail_args(args, overall_forms, "")
process_overrides(args, overall_forms, "")
if case_will_be_displayed(args, "pauc") then
insert_if_not(args.internal_notes, paucal_internal_note)
end
-- if IRREGMARKER is anywhere in text, remove all instances and put
-- at the end before any notes.
local function clean_irreg_marker(case, text)
if rfind(text, IRREGMARKER) then
text = rsub(text, IRREGMARKER, "")
local entry, notes = m_table_tools.separate_notes(text)
if case_will_be_displayed(args, case) then
insert_if_not(args.internal_notes, IRREGMARKER .. " Irregular.")
args.any_irreg = true
args.any_irreg_case[case] = true
end
return entry .. IRREGMARKER .. notes
else
return text
end
end
-- set final args[case] and clean up IRREGMARKER.
for _, case in ipairs(all_cases) do
args[case] = overall_forms[case]
if args[case] then
local cleaned_forms = {}
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
ru = clean_irreg_marker(case, ru)
if tr then
tr = clean_irreg_marker(case, tr)
end
table.insert(cleaned_forms, {ru, tr})
end
args[case] = cleaned_forms
end
end
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). We need to do this somewhat complicated procedure to get overrides
-- to work correctly, e.g. acc_sg overrides of feminine and neuter nouns
-- (such as мать and полслова) and gen_sg/gen_pl overrides of masculine
-- animate nouns. We also ran into an issue with words like мазло that are
-- neuter-form but can be both masculine animate (in which case the
-- acc sg inherits from the genitive) and neuter animate (in which case the
-- acc sg has the fixed ending -о, same as nominative, despite the animacy).
-- Remember also that the animate/inanimate accusative variants are the ones
-- displayed, not the plain acc_sg/acc_pl ones.
if not args.any_overridden.acc_sg_an then
if acc_sg_overridden then
args.acc_sg_an = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_an = args.acc_sg or args.a == "i" and args.nom_sg or args.gen_sg or args.acc_sg_an
end
end
if not args.any_overridden.acc_sg_in then
if acc_sg_overridden then
args.acc_sg_in = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_in = args.acc_sg or args.a == "a" and args.gen_sg or args.nom_sg or args.acc_sg_in
end
end
if not args.any_overridden.acc_pl_an then
if acc_pl_overridden then
args.acc_pl_an = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_an = args.acc_pl or args.a == "i" and args.nom_pl or args.gen_pl or args.acc_pl_an
end
end
if not args.any_overridden.acc_pl_in then
if acc_pl_overridden then
args.acc_pl_in = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_in = args.acc_pl or args.a == "a" and args.gen_pl or args.nom_pl or args.acc_pl_in
end
end
-- Try to set the values of acc_sg and acc_pl. The only time we can't is
-- when the noun is bianimate and the anim/inan values are different.
-- This is used primarily for generate_forms() and generate_multi_forms(),
-- since we don't actually display these forms.
if args.a == "a" then
args.acc_sg = args.acc_sg or args.acc_sg_an
args.acc_pl = args.acc_pl or args.acc_pl_an
elseif args.a == "i" then
args.acc_sg = args.acc_sg or args.acc_sg_in
args.acc_pl = args.acc_pl or args.acc_pl_in
else -- bianimate
args.acc_sg = args.acc_sg or m_table.deepEquals(args.acc_sg_in, args.acc_sg_an) and args.acc_sg_in or nil
args.acc_pl = args.acc_pl or m_table.deepEquals(args.acc_pl_in, args.acc_pl_an) and args.acc_pl_in or nil
end
end
-- Subfunction of concat_word_forms(), used to implement recursively
-- generating all combinations of elements from WORD_FORMS (a list, one
-- element per word, of a list of the forms for a word, each of which is a
-- two-element list of {RUSSIAN, TR}) and TRAILING_FORMS (a list of forms, the
-- accumulated suffixes for trailing words so far in the recursion process,
-- again where each form is a two-element list {RUSSIAN, TR}). Each time we
-- recur we take the last FORMS item off of WORD_FORMS and to each form in
-- FORMS we add all elements in TRAILING_FORMS, passing the newly generated
-- list of items down the next recursion level with the shorter WORD_FORMS.
-- We end up returning a list of concatenated forms, where each list item
-- is a two-element list {RUSSIAN, TR}.
local function concat_word_forms_1(word_forms, trailing_forms)
if #word_forms == 0 then
local retforms = {}
for _, form in ipairs(trailing_forms) do
local ru, tr = form[1], form[2]
-- Remove <insa> and <insb> markers; they've served their purpose.
ru = rsub(ru, "<ins[ab]>", "")
tr = tr and rsub(tr, "<ins[ab]>", "")
table.insert(retforms, {ru, tr})
end
return retforms
else
local last_form_info = table.remove(word_forms)
local last_forms, joiner = last_form_info[1], last_form_info[2]
local new_trailing_forms = {}
for _, form in ipairs(last_forms) do
for _, trailing_form in ipairs(trailing_forms) do
-- If form to prepend is empty, don't add the joiner; this
-- is principally used in overall overrides, where we stuff
-- the entire override into the last word
local full_form = form[1] == "" and trailing_form or
com.concat_paired_russian_tr(form,
com.concat_paired_russian_tr(joiner, trailing_form),
"movenotes")
if rfind(full_form[1], "<insa>") and rfind(full_form[1], "<insb>") then
-- REJECT! So we don't get mixtures of the two feminine
-- instrumental singular endings.
else
table.insert(new_trailing_forms, full_form)
end
end
end
return concat_word_forms_1(word_forms, new_trailing_forms)
end
end
-- Generate a list of overall forms by concatenating the per-word forms.
-- PER_WORD_INFO comes from args.per_word_info and is a list of
-- WORD_INFO items, one per word, each of which a two element list of
-- WORD_FORMS (a table listing the forms for each case) and JOINER (a string).
-- We loop over all possible combinations of elements from each word's list
-- of forms for the given case; this requires recursion.
concat_word_forms = function(per_word_info, case)
local word_forms = {}
-- Gather the appropriate word forms. We have to recreate this anew
-- because it will be destructively modified by concat_word_forms_1().
for _, word_info in ipairs(per_word_info) do
table.insert(word_forms, {word_info[1][case], word_info[2]})
end
-- We need to start the recursion with the second parameter containing
-- one blank element rather than no elements, otherwise no elements
-- will be propagated to the next recursion level.
return concat_word_forms_1(word_forms, {{""}})
end
local accel_forms = {
nom_sg = "nom|s",
nom_sg_linked = "nom|s",
nom_pl = "nom|p",
nom_pl_linked = "nom|p",
gen_sg = "gen|s",
gen_pl = "gen|p",
dat_sg = "dat|s",
dat_pl = "dat|p",
acc_sg_an = "an|acc|s",
acc_pl_an = "an|acc|p",
acc_sg_in = "in|acc|s",
acc_pl_in = "in|acc|p",
ins_sg = "ins|s",
ins_pl = "ins|p",
pre_sg = "pre|s",
pre_pl = "pre|p",
loc = "loc|s",
loc_pl = "loc|p",
voc = "voc|s",
voc_pl = "voc|p",
par = "par|s",
par_pl = "par|p",
count = "count form",
pauc = "pau",
}
-- Make the table
make_table = function(args)
local data = {}
data.after_title = " " .. args.heading
data.number = args.nonumber and "" or numbers[args.n]
local lemma_forms = args[args.n == "p" and "nom_pl" or "nom_sg"]
data.lemma = nom.show_form(args.explicit_lemma and {{args.explicit_lemma, args.explicit_lemmatr}} or
args[args.n == "p" and "nom_pl_linked" or "nom_sg_linked"], "lemma", nil, nil)
data.title = args.title or format(args.old and old_title_temp or title_temp, data)
local sg_an_in_equal = m_table.deepEquals(args.acc_sg_an, args.acc_sg_in)
local pl_an_in_equal = m_table.deepEquals(args.acc_pl_an, args.acc_pl_in)
for _, case in ipairs(displayable_cases) do
local accel_form = accel_forms[case]
if not accel_form then
error("Something wrong, can't find accelerator form for " .. case)
end
if (sg_an_in_equal and (case == "acc_sg_an" or case == "acc_sg_in") or
pl_an_in_equal and (case == "acc_pl_an" or case == "acc_pl_in")) then
accel_form = rsub(accel_form, "^[ai]n|", "")
end
if args.n == "p" then
accel_form = rsub(accel_form, "|p$", "")
end
data[case] = nom.show_form(args[case], false, accel_form, lemma_forms, "remove monosyllabic accents only lemma")
end
local temp = nil
if args.n == "s" then
data.nom_x = data.nom_sg
data.gen_x = data.gen_sg
data.dat_x = data.dat_sg
data.acc_x_an = data.acc_sg_an
data.acc_x_in = data.acc_sg_in
data.ins_x = data.ins_sg
data.pre_x = data.pre_sg
if sg_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
elseif args.n == "p" then
data.nom_x = data.nom_pl
data.gen_x = data.gen_pl
data.dat_x = data.dat_pl
data.acc_x_an = data.acc_pl_an
data.acc_x_in = data.acc_pl_in
data.ins_x = data.ins_pl
data.pre_x = data.pre_pl
data.par = data.par_pl
data.loc = data.loc_pl
data.voc = data.voc_pl
if pl_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
else
if pl_an_in_equal then
temp = "both_numbers"
elseif sg_an_in_equal then
temp = "both_numbers_split_animacy_plural_only"
else
temp = "both_numbers_split_animacy"
end
end
for _, extra_case in ipairs({
{"par", "partitive"},
{"loc", "locative"},
{"voc", "vocative"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "s" and args.n ~= "p" and args.any_overridden[case .. "_pl"] then
if not args.any_overridden[case] then
data[case] = ""
end
template = extra_case_template_with_plural
elseif args.n ~= "p" and args.any_overridden[case] or args.n == "p" and args.any_overridden[case .. "_pl"] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
for _, extra_case in ipairs({
{"count", "count form"},
{"pauc", "paucal"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "p" and args.any_overridden[case] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
local notes = get_arg_chain(args, "notes", "notes")
local all_notes = {}
for _, note in ipairs(args.internal_notes) do
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
for _, note in ipairs(notes) do
-- Here too.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
data.notes = table.concat(all_notes, "<br />")
data.notes_clause = data.notes ~= "" and format(notes_template, data) or ""
return format(templates[temp], data)
end
function extra_case_template(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
|
|-]===]):format(colspan)
end
function extra_case_template_with_plural(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
| {\op}{case}_pl{\cl}
|-]===]):format(colspan)
end
notes_template = [===[
<div style="width:100%;text-align:left;background:var(--wikt-palette-lightblue, #d9ebff);">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame" data-toggle-category="လဟုတ်စှ်ေ" style="max-width:MINWIDTHem">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);">{title}<span style="font-weight:normal;">{after_title}</span> </div>
<div class="NavContent">
{\op}| style="table-layout:fixed; text-align:center; max-width:MINWIDTHem; width:100%;" class="inflection inflection-table"
|- class="rowgroup"
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[|-{par_clause}{loc_clause}{voc_clause}{count_clause}{pauc_clause}
|{\cl}{notes_clause}</div></div></div>]===]
end
templates["both_numbers"] = template_prelude("45") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_sg_in}
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy_plural_only"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 rowspan=2 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["one_number"] = template_prelude("30") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
templates["one_number_split_animacy"] = template_prelude("35") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| {acc_x_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
return export
4cy3q0eqyhw1gjubo1rk46be91u9po6
399800
399799
2026-07-21T03:07:59Z
咽頭べさ
33
399800
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
nouns.
Author: Benwing, rewritten from early version by Wikitiki89
Form of arguments: One of the following:
1. LEMMA|DECL|PLSTEM (all arguments optional)
2. ACCENT|LEMMA|DECL|PLSTEM (all arguments optional)
3. multiple sets of arguments separated by the literal word "or"
Arguments:
ACCENT: Accent pattern (a b c d e f b' d' f' f''). Multiple values can
be specified, separated by commas. If omitted, defaults to a or b
depending on the position of stress on the lemma or
explicitly-specified declension.
LEMMA: Lemma form (i.e. nom sg or nom pl), with appropriately-placed
stress; or the stem, if an explicit declension is specified
(in this case, the declension usually looks like an ending, and
the stem is the portion of the lemma minus the ending). In the
first argument set (i.e. first set of arguments separated
by "or"), defaults to page name; in later sets, defaults to lemma
of previous set. A plural form can be given, and causes argument
n= to default to n=p (plural only). Normally, an accent is
required if multisyllabic, and unaccented monosyllables with
automatically be stressed; prefix with * to override both behaviors.
DECL: Declension field. Normally omitted to autodetect based on the
lemma form; see below.
PLSTEM: special plural stem (defaults to stem of lemma)
Additional named arguments:
a: animacy (a/an/anim = animate, i/in/inan = inanimate, b/bi/both/ai = both
(listing animate first in the headword), ia = both (listing inanimate
first in the headword), otherwise inanimate)
n: number restriction (p = plural only, s = singular only, b = both;
defaults to both unless the lemma is plural, in which case it
defaults to plural only)
CASE_NUM or acc_NUM_ANIM or par/loc/voc: override (or multiple
values separated by commas) for case/number combination;
forms auto-linked; can have raw links in it, can have an
ending "note" (*, +, 1, 2, 3, etc.)
pltail: Specify something (usually a * or similar) to attach to
the end of the last plural form when there's more than one. Used in
conjunction with notes= to indicate that alternative plural forms
are obsolete, poetic, etc.
pltailall: Similar pltail= but attaches to all plural forms.
Typically used in conjunction with notes= to make a comment about
the plural as a whole (e.g. it's mostly hypothetical, rare and
awkward, etc.).
sgtail, sgtailall: Same as pltail=, pltailall= but for the singular.
obltail, obltailall: Same as pltail=, pltailall= but for oblique cases
(not the nominative or accusative).
CASE_NUM_tail: Attach the argument to the end of the last form
(whether there's one or more than one) for the particular
case/number combination. Note that this doesn't work quite like
pltail= or sgtail= in that it doesn't skip adding the argument
when there's only one form.
CASE_NUM_tailall: Attach the argument to the end of all forms
specified for the particular case/number combination. Similar to
pltailall= or sgtailall=.
suffix: Add a suffix such as ся to all forms.
prefix: Add a prefix to all forms.
plhyp, plhypall, CASE_NUM_hyp, etc.: Same as pltail, pltailall,
CASE_NUM_tal, etc. but specify that the marked forms are
mostly hypothetical or rare/awkard. Generally you will want
plhypall=y to mark the plural as hypothetical.
Per word named arguments:
All of the above named arguments have per-word variants, e.g.
a1, a2, ...; n1, n2, ...; CASE_NUM1, CASE_NUM2, ...;
pltail1, pltail2, ...; etc. These apply to the individual words of a
form.
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
par: partitive
loc: locative
voc: vocative
Number abbreviations:
sg: singular
pl: plural
Animacy abbreviations:
an: animate
in: inanimate
Declension field:
One of the following for regular nouns:
(blank)
GENDER
-VARIANT
GENDER-VARIANT
$
DECLTYPE
DECLTYPE/DECLTYPE
(also, can append various special-case markers to any of the above)
Or one of the following for adjectival nouns:
+
+ь
$
+short, +mixed or +proper
+DECLTYPE
GENDER if present is m, f, n or 3f; for regular nouns, required if the
lemma ends in -ь or is plural, ignored otherwise. 3f is the same
as f but in the case of a plural lemma in -и, detects a
third-declension feminine with singular in -ь rather than a
first-declension feminine with singular in -а or -я.
VARIANT is one way of requesting variant declensions (see also special
case (1) for variant nom pls, and special case (2) for variant
gen pls). The currently allowed values are -ья (will select a
mixed declension that has some normal declension in its singular
and the -ья plural declension); -ин (for animate masculine nouns
in -ин with plural in -е -- note that this is autodetected in the
majority of cases where the ending in -янин or -анин); -ишко
(used for inanimate neuter-form diminutive masculine nouns in
-ишко [also сараю́шко] with nom pl -и and colloquial feminine-ending
alternants in some singular cases); -ище (similar to -ишко but
used for *animate* augmentative masculine neuter-form nouns in
-ище). Variants -ишко and -ище must be given with with special
case (1).
$ is indeclinable words. It is principally useful in multiword
expressions where some of the words are indeclinable.
DECLTYPE is an explicit declension type. Normally you shouldn't use
this, and should instead let the declension type be autodetected
based on the ending, supplying the appropriate hint if needed
(gender for regular nouns, +ь for adjectives). If provided, the
declension type is usually the same as the ending, and if present,
the lemma field should be just the stem, without the ending.
Possibilities for regular nouns are (blank) or # for hard-consonant
declension, а, я, о, е or ё, е́, й, ья, ье or ьё, ь-m, ь-f,
ин, ёнок or онок or енок, ёночек or оночек or еночек, мя,
-а or #-а, ь-я, й-я, о-и or о-ы, -ья or #-ья, $ (indeclinable).
Old-style (pre-reform) declensions use ъ instead of (blank), ъ-а
instead of -а, ъ-ья instead of -ья, and инъ, ёнокъ/онокъ/енокъ,
ёночекъ/оночекъ/еночекъ instead of the same without terminating ъ.
The declensions can also be written with an accent on them; this
chooses the same declension (except for е vs. е́), but causes
ACCENT to default to pattern b instead of a.
For adjectival nouns, you should normally supply just + and let
the ending determine the declension; supply +ь in the case of a
possessive adjectival noun in -ий, which have an extra -ь- in
most endings compared with normal adjectival nouns in -ий, but
which can't be distinguished based on the nominative singular.
You can also supply +short, +mixed or +proper, which constrains
the declension appropriately but still autodetects the
gender-specific and stress-specific variant. If you do supply
a specific declension type, as with regular nouns you need to
omit the ending from the lemma field and supply just the stem.
Possibilities are +ый, +ое, +ая, +ій, +ее, +яя, +ой, +о́е, +а́я,
+ьій, +ье, +ья, +-short or +#-short (masc), +о-short,
+о-stressed-short or +о́-short, +а-short, +а-stressed-short or
+а́-short, and similar for -mixed and -proper (except there aren't
any stressed mixed declensions).
DECLTYPE/DECLTYPE is used for nouns with one declension in the
singular and a different one in the plural, for cases that
PLVARIANT and special case (1) below don't cover.
Special-case markers:
(1) for Zaliznyak-style alternative nominative plural ending:
-а or -я for masculine, -и or -ы for neuter
(2) for Zaliznyak-style alternative genitive plural ending:
-ъ/none for masculine, -ей for feminine, -ов(ъ) for neuter,
-ей for plural variant -ья
* for reducibles (nom sg or gen pl has an extra vowel before the
final consonant as compared with the stem found in other cases)
;ё for Zaliznyak-style alternation between last е in stem and ё
TODO:
1. Multi-word issues:
-- FIXME: Make sure internal_notes handled correctly; we may run into issues
with multiple internal notes from different words, if we're not careful
to use different footnote symbols for each type of footnote (which we
don't do currently). [NOT DONE, MAY NOT DO]
-- Handling default lemma: With multiple words, we should probably split
the page name on spaces and default each word in turn [NOT DONE, MAY
NOT DO]
2a. FIXME: For -ишко diminutives and -ище augmentatives, should add an
appropriate category of some sort (currently marked by colloqfem= in
category).
2b. FIXME: Adding a note to dat_sg also adds it to loc_sg when it exists;
seems wrong. See луг.
2c. FIXME: When you have both d' and f in feminines and you use sgtail=*,
you get two *'s. See User:Benwing2/test-ru-noun-debug.
3. ADJECTIVE FIXMES:
3a. FIXME: Change calls to ru-adj11 to use the new proper name support in
ru-adjective.
3b. FIXME: Test that omitting a manual form in ru-adjective leaves the form as
a big dash.
3c. FIXME: какой-либо and какой-то display genitives with translit -go
instead of -vo. To fix this properly requires implementing real
manual translit for adjectives.
3d. FIXME: Implement real manual translit for adjectives.
5. [FIXME: Consider adding an indicator in the header line when the ё/e
alternation occurs. This is a bit tricky to calculate: If special case
;ё is given, but also if ё occurs in the stem and the accent pattern is
as follows -- for sg-only, b' d' f' f'', also b d f if the noun is masc
or 3rd-decl fem (i.e. nom-sg ending is non-syllabic); for pl-only,
e f f' f'', also b b' c if the gen pl is non-syllabic; for sg/pl,
any but a or b, also b if either nom sg or gen pl is non-syllabic. But
it gets more complicated due to overrides. An alternative is to check
all forms to see if ё is present in some but not all; but this is
tricky also because e.g. reducibles frequently have ё/null alternation,
which doesn't count, and some endings have е or ё in them, which also
doesn't count. If we were to do it this way, we'd have to (a) count
the number of е's in the form(s) with ё and verify that there's at least
one form without ё and with one more е than in the form(s) with ё
(and it gets trickier if different forms with ё have different numbers of
е in them, although that is probably rare); and (b) ignore the appropriate
endings (the best way to do this would probably be to look at the actual
suffixes that were generated in args.suffixes and chop off any matching
ending in the actual form(s), but also chop off final -е/ё, as well as
-ев(ъ)/-ёв(ъ)/-ей/-ёй in the gen pl, which is frequently overridden,
unless perhaps the stem ends in the same way). It'd probably not
possible to do this in a 100% foolproof way but can be "good enough" for
nearly all circumstances.] [MIGHT BE TOO MUCH WORK]
6. HEADWORD FIXMES:
6a. FIXME: In ru-headword, create a category for words whose gender doesn't
match the form. (This is easy to do for ru-noun+ but harder for ru-noun.
We would need to do limited autodetection of the ending: for singulars,
-а/я should be feminine, -е/о/ё should be neuter, -ь should be masculine
or feminine, anything else should be masculine; for plurals, -и/ы should
be masculine or feminine, -а/я should be neuter except that -ія can be
feminine or neuter due to old-style adjectival pluralia tantum nouns,
anything else can be any gender.)
6b. FIXME: Recognize indeclinable nouns and indicate as indeclinable. Probably
should work by checking the case forms to see if they're the same.
9. FIXME: Change stress-pattern detection and overriding to happen inside of
looping over the two parts of a slash decl. Requires that the loop over
the two parts happen outside of the loop over stress patterns. Requires
that the category code get split into two parts, one to handle combined
singular/plural categories that goes outside the two loops, and one to
handle everything else that goes inside the two loops.
10. FIXME: override_matches_suffix() had a free variable reference to ARGS
in it, which should have triggered an error whenever there was a nom_sg or
nom_pl override but didn't. Is there an error causing this never to be
called? Check.
11a. FIXME: In a multiword lemma, using loc2=+ causes only the second word
to get linked instead of the whole expression. Same for par2=+, voc2=+.
11b. FIXME: Using loc=+ with a multiword lemma should do the right thing, same
as if locN=+ is specified for each individual word. Instead it generates
the locative as a whole from the dative, which fails e.g. if some of the
words are adjectival. Same for par=+, voc=+.
13. Multi-word issues:
-- Setting n=pl when auto-detecting a plural lemma. How does that interact
with multi-word stuff? (DONE)
-- compute_heading() -- what to do with multiple words? I assume we should
display info on the first noun (non-indeclinable, non-adjectival), and
on the first adjectival word otherwise, and finally on an indeclinable word (DONE)
-- args.genders -- it should presumably come from the same word as is used
in compute_heading(); but we should allow the overall gender to be
overridden, at least in ru-noun+ (DONE)
-- Bug in args.suffix: Gets added to every word in attach_with() and then
again at the end, after pltail and such. Needs to be added to the
last word only, before pltail. Need also suffixN for individual words.
(DONE, NEEDS TESTING)
-- Should have ..N versions of pltail and variants. (DONE, NEEDS TESTING)
-- Need to handle overrides of acc_sg, acc_pl (DONE)
-- Overrides of nom_sg/nom_pl should also override acc_sg/acc_pl if it
was originally empty and the animacy is inanimate; similarly for
gen_sg/gen_pl and animates; this needs to work both for per-word and
overall overrides. (DONE)
-- do_generate_forms(_multi) need to run part of make_table(), enough to
combine all per_word_info into single lists of forms and store back
into args[case]. (DONE, NEEDS TESTING)
-- In generate_forms, should probably check if a=="i" and only return
acc_sg_in as acc_sg=; or if a=="a" and only return acc_sg_an as acc_sg=;
in old/new comparison code, do something similar, also when a=="b"
check if acc_sg_in==acc_sg_an and make it acc_sg; when a=="b" and the
_in and _an variants are different, might need to ignore them or check
that acc_sg_in==nom_sg and acc_sg_an==gen_sg; similarly for _pl
(DONE, NEEDS TESTING)
-- Need to test with multiple words! [DONE]
-- Current handling of <adj> won't work properly with multiple words;
will need to translate word-by-word in that case (should be solved by
manual-translit branch) [DONE]
14. In multiple-words branch, fix ru-decl-noun-multi so it recognizes
things like *, (1), (2) and ; without the need for a separator. Consider
using semicolon as a separator, since we already use it to separate ё
from a previous declension. Maybe use $ or ~ for an indeclinable word; don't
use semicolon. [IMPLEMENTED. NEED TO TEST.]
16. [Consider having ru-noun+ treat par= as a second genitive in
the headword, as is done with край] [WON'T DO]
17. [FIXME: Consider removing slash patterns and instead handling them by
allowing additional declension flags 'sg' and 'pl'. This simplifies the
various special cases caused by slash declensions. It would also be
possible to remove the special plural stem, which would get rid of more
special cases. On the other hand, it makes it more complicated to support
plural variant -ья with all singular types, and the category code that
displays things like "Russian nouns with singular -X and plural -Y"
also gets more complicated, and there's something convenient and intuitive
about plural stems, and slash declensions are also convenient and at least
somewhat intuitive. One possibility is to externally allow slash
declensions and special plural stems and rewrite them internally to
separate stems with 'sg' and 'pl' declension flags; but there are still
the two coding issues mentioned above.]
18. [FIXME: Consider redoing slash patterns so they operate at the outer
level, i.e. things like special cases apply separately in the singular
and plural part of the slash pattern.]
19. In ru-noun, don't recognize -а with m as plural unless (1)
or n=pl is also given, because there are masculine words with the
feminine ending. Check using the test code whether this changes
anything. Also check if there are other similar cases (neuter with
-и isn't parallel because -и is always plural). [IMPLEMENTED. NEED TO TEST.]
19a. Internal notes weren't propagated properly from adjectives.
[IMPLEMENTED. NEED TO TEST.]
19b. Add support for -ишко and -ище variants (p. 74 of Z),
which conversationally and/or colloquially have feminine endings in
certain cases. [IMPLEMENTED. NEED TO TEST. MAKE SURE THE INTERNAL NOTES
APPEAR.]
19d. For masculine animate neuter-form nouns, the accusative singular
ends in -а (-я soft) instead of -о. [IMPLEMENTED. NEED TO TEST.
NOTE: Currently this variant only can be selected using new-style
arguments where the gender can be given. Perhaps we should consider
allowing gender to be specified with old-style explicit declensions.]
21. Put back gender hints for pl adjectival nouns; used by ru-noun+.
[IMPLEMENTED. NEED TO TEST.]
23. Mixed and proper-noun adjectives have built-in notes. We need to
handle those notes with an "internal_notes" section similar to what is used
in the adjective module. [IMPLEMENTED. NEED TO TEST.]
24. Adjective detection code here needs to work the same as for the
adjective module, in particular in the handling of short, stressed-short,
mixed, proper, stressed-proper. [IMPLEMENTED. NEED TO TEST.]
25. Consider simplifying plural-variant code to only allow -ья as a
plural variant [and maybe even change that to be something like (1')].
[IMPLEMENTED REDUCTION OF PLURAL VARIANTS TO -ья; PLURAL-VARIANT CODE
STILL COMPLEX, THOUGH. NEED TO TEST.]
26. Automatically superscript *, numbers and similar things at the
beginning of a note. Also do this in adjective module. [IMPLEMENTED.
NEED TO TEST.]
28. Make the check for multiple stress patterns (categorizing/tracking)
smarter, to keep a list of them and check at the end, so we handle
multiple stress patterns specified through different arg sets.
[IMPLEMENTED; NEED TO TEST.]
29. More sophisticated handling of user-requested plural variant vs. special
case (1) vs. plural-detected variant. [IMPLEMENTED. NEED TO TEST FURTHER.]
30. Solution to ambiguous plural involving gender spec "3f". [IMPLEMENTED;
NEED TO TEST. Use запчасти, новости.]
33. With pluralia tantum adjectival nouns, we don't know the gender.
By default we assume masculine (or feminine for old-style -ія nouns) and
currently this goes into the category, but shouldn't. [IMPLEMENTED.]
39. [Eventually: Even with decl type explicitly given, the full stem with
ending should be included.] [MAY NEVER IMPLEMENT]
40. [Get error "Unable to dereduce" with strange noun ва́йя, what should
happen?] [WILL NOT FIX; USE AN OVERRIDE]
41. In творог, module generates partitive творогу́ when it should copy the
dative творогу́,тво́рогу. (DONE)
42. [[груз 200]] doesn't work. Interprets 200 as a footnote symbol.
43. When converting е -> ё not after cons and with translit, we should
convert e -> o to avoid double j. (DONE)
44. FIXME: In ро́вня/ровня́, similarly with неровня, marks genitive plural
ровня́ as irregular even though it isn't. (NOT OUR ERROR; THE DECLENSIONS
OF THESE NOUNS MARKED THE ENDING-STRESSED VARIANTS WITH (2).)
]=]--
local m_utilities = require("Module:utilities")
local m_table = require("Module:table")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local m_ru_adj = require("Module:ru-adjective")
local m_str_utils = require("Module:string utilities")
local scriptutils = require("Module:script utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
local Latn = require("Module:scripts").getByCode("Latn")
local format = m_str_utils.format
local rfind = m_str_utils.find
local rsubn = m_str_utils.gsub
local rmatch = m_str_utils.match
local rsplit = m_str_utils.split
local u = m_str_utils.char
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same. Eventually consider removing this;
-- but useful as new code is created.
local test_new_ru_noun_module = false
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local DIA = u(0x0308) -- diaeresis = ̈
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder, matching ru-common
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
local paucal_marker = "*"
local paucal_internal_note = "* Used with the numbers 1.5, 2, 3, 4 and higher numbers after 20 ending in 2, 3, and 4."
-- text class to check lowercase arg against to see if Latin text embedded in it
local latin_text_class = "[a-zščžěáéíóúýàèìòùỳâêîôûŷạẹịọụỵȧėȯẏ]"
-- Forward functions
local generate_forms_1
local determine_decl
local handle_forms_and_overrides
local handle_overall_forms_and_overrides
local concat_word_forms
local make_table
local detect_adj_type
local detect_stress_pattern
local override_stress_pattern
local determine_stress_variant
local determine_stem_variant
local is_reducible
local is_dereducible
local add_bare_suffix
local attach_stressed
local do_stress_pattern
local canonicalize_override
-- 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
-- version of rfind() that lowercases its string first, for case-insensitive matching
local function rlfind(term, foo)
return rfind(ulower(term), foo)
end
local function track(page)
m_debug.track("ru-noun/" .. page)
return true
end
-- version of m_table.insertIfNot() that makes sure 'false' doesn't get inserted by mistake.
local function insert_if_not(foo, bar)
assert(bar ~= false)
m_table.insertIfNot(foo, bar)
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-- FIXME: Move to utils
-- Iterate over a chain of parameters, FIRST then PREF2, PREF3, ...,
-- inserting into LIST (newly created if omitted). Return LIST.
local function get_arg_chain(args, first, pref, list)
if not list then
list = {}
end
local val = args[first]
local i = 2
while val do
table.insert(list, val)
val = args[pref .. i]
i = i + 1
end
return list
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
local function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
local function rutr_pairs_equal(term1, term2)
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
local ru1entry, ru1notes = m_table_tools.separate_notes(m_links.remove_links(ru1))
local ru2entry, ru2notes = m_table_tools.separate_notes(m_links.remove_links(ru2))
if ru1entry ~= ru2entry then
return false
end
local tr1entry, tr1notes
local tr2entry, tr2notes
if tr1 then
tr1entry, tr1notes = m_table_tools.separate_notes(tr1)
end
if tr2 then
tr2entry, tr2notes = m_table_tools.separate_notes(tr2)
end
if tr1entry == tr2entry then
return true
elseif type(tr1entry) == type(tr2entry) then
return false
else
tr1entry = tr1entry or com.translit_no_links(ru1entry)
tr2entry = tr2entry or com.translit_no_links(ru2entry)
return tr1entry == tr2entry
end
end
local function contains_rutr_pair(list, pair)
for _, item in ipairs(list) do
if rutr_pairs_equal(item, pair) then
return true
end
end
return false
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
args[pname] = ine(param)
end
return args
end
-- Old-style declensions.
local declensions_old = {}
-- New-style declensions; computed automatically from the old-style ones,
-- for the most part.
local declensions = {}
-- Internal notes for old-style declensions.
local internal_notes_table_old = {}
-- Same for new-style declensions.
local internal_notes_table = {}
-- Category and type information corresponding to declensions: These may
-- contain the following fields: 'singular', 'plural', 'decl', 'hard', 'g',
-- 'suffix', 'gensg', 'irregpl', 'alt_nom_pl', 'cant_reduce', 'ignore_reduce',
-- 'stem_suffix'.
--
-- 'singular' is used to construct a category of the form
-- "Russian nouns SINGULAR". If omitted, a category is constructed of the
-- form "Russian nouns ending in -ENDING", where ENDING is the actual
-- nom sg ending shorn of its acute accents; or "Russian nouns ending
-- in suffix -ENDING", if 'suffix' is true. The value of SINGULAR can be
-- one of the following: a single string, a list of strings, or a function,
-- which is passed one argument (the value of ENDING that would be used to
-- auto-initialize the category), and should return a single string or list
-- of strings. Such a category is only constructed if 'gensg' is true.
--
-- 'plural' is analogous but used to construct a category of the form
-- "Russian nouns with PLURAL", and if omitted, a category is constructed
-- of the form "Russian nouns with plural -ENDING", based on the actual
-- nom pl ending shorn of its acute accents. Currently no plural category
-- is actually constructed.
--
-- In addition, a category may normally constructed from the combination of
-- 'singular' and 'plural', appropriately defaulted; e.g. if both are present,
-- the combined category will be "Russian nouns SINGULAR with PLURAL" and
-- if both are missing, the combined category will be
-- "Russian nouns ending in -SGENDING with plural -PLENDING" (or
-- "Russian nouns ending in suffix -SGENDING with plural -PLENDING" if
-- 'suffix' is true). Note that if either singular or plural or both
-- specifies a list, looping will occur over all combinations. Such a
-- category is constructed only if 'irregpl' or 'alt_nom_pl' or 'suffix'
-- is true or if the declension class is a slash class.
--
-- 'decl' is "1st", "2nd", "3rd" or "indeclinable"; 'hard' is "hard", "soft"
-- or "none"; 'g' is "m", "f", "n" or "none"; these are all traditional
-- declension categories.
--
-- If 'suffix' is true, the declension type includes a long suffix
-- added to the string that itself undergoes reducibility and such, and so
-- reducibility cannot occur in the stem minus the suffix. Categories will
-- be created for the suffix.
--
-- 'alt_nom_pl' indicates that the declension has an alternative nominative
-- plural (corresponding to Zaliznyak's special case 1; compare special case 2
-- for alternative genitive plural). 'irregpl' indicates that the entire
-- plural is irregular.
--
-- In addition to the above categories, additional more specific categories
-- are constructed based on the final letter of the stem, e.g.
-- "Russian velar-stem 1st-declension hard nouns". See calls to
-- com.get_stem_trailing_letter_type(). 'stem_suffix', if present, is added to
-- the end of the stem when get_stem_trailing_letter_type() is called.
-- This is the only place that 'stem_suffix' is used. This is for use with
-- the '-ья' and '-ье' declension types, so that the trailing letter is
-- 'ь' and not whatever precedes it.
--
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
-- Category/type info corresponding to old-style declensions; see above.
local declensions_old_cat = {}
-- Category/type info corresponding to new-style declensions. Computed
-- automatically from the old-style ones, for the most part. Same format
-- as the old-style ones.
local declensions_cat = {}
-- Table listing aliases of old-style declension classes.
local declensions_old_aliases = {}
-- Table listing aliases of new-style declension classes; computed
-- automatically from the old-style ones.
local declensions_aliases = {}
local stress_patterns = {}
-- Set of patterns with ending-stressed genitive plural.
local ending_stressed_gen_pl_patterns = {}
-- Set of patterns with ending-stressed prepositional singular.
local ending_stressed_pre_sg_patterns = {}
-- Set of patterns with ending-stressed dative singular.
local ending_stressed_dat_sg_patterns = {}
-- Set of patterns with all singular forms ending-stressed.
local ending_stressed_sg_patterns = {}
-- Set of patterns with all plural forms ending-stressed.
local ending_stressed_pl_patterns = {}
local declinable_cases_except_accusative = {
"nom_sg", "gen_sg", "dat_sg", "ins_sg", "pre_sg",
"nom_pl", "gen_pl", "dat_pl", "ins_pl", "pre_pl",
}
local accusative_cases_unsplit_animacy = {
"acc_sg", "acc_pl",
}
local accusative_cases_split_animacy = {
"acc_sg_an", "acc_sg_in", "acc_pl_an", "acc_pl_in",
}
local lemma_linked_cases = {
"nom_sg_linked", "nom_pl_linked",
}
local overridable_only_cases = {
"par", "loc", "voc", "par_pl", "loc_pl", "voc_pl", "count", "pauc",
}
local overridable_only_cases_set = m_table.listToSet(overridable_only_cases)
-- List of all cases that are declined normally.
local decl_cases = m_table.append(declinable_cases_except_accusative, accusative_cases_unsplit_animacy)
-- List of all cases that can be overridden (includes all cases except the "linked" lemma case variants). Also
-- currently the same as the cases returned by export.generate_forms().
local overridable_cases = m_table.append(decl_cases, accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases that can be displayed (includes all cases except plain accusatives).
local displayable_cases = m_table.append(declinable_cases_except_accusative, lemma_linked_cases,
accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases, including those that are declined normally (nom/gen/dat/acc/ins/pre sg and pl), plus
-- animate/inanimate accusative variants (computed automatically as appropriate from the previous cases), plus
-- additional overridable cases (loc/par/voc and plural), plus the "linked" lemma case variants used in ru-noun+
-- headwords (nom_sg_linked, nom_pl_linked, whose values come from nom_sg and nom_pl but may have additional embedded
-- links if they were given in the lemma).
local all_cases = m_table.append(overridable_cases, lemma_linked_cases)
local function english_case_description(case)
if case == "par" or case == "loc" or case == "voc" then
-- For historical reasons, the singular of these cases doens't include "_sg" in their code.
case = case .. "_sg"
end
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
par="partitive", loc="locative", voc="vocative",
count="count form", pauc="paucal form",
})
engcase = rsub(engcase, "(_[a-z]*)", {
_sg=" singular", _pl=" plural",
_an="", _in="",
--_an=" animate", _in=" inanimate"
})
return engcase
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
-- FIXME! Move below the main code
-- FIXME!! Consider deleting most of this tracking code once we've enabled
-- all the categories. Note that some of the tracking categories aren't
-- completely redundant; e.g. we have tracking pages that combine decl and
-- stress classes, such as "а/a" or "о-и/d'", which are more or less
-- equivalent to stem/gender/stress categories, but we also have the same
-- prefixed by "reducible-stem/" for reducible stems.
local function tracking_code(stress, orig_decl, decl, args, n, islast)
assert(orig_decl)
assert(decl)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
if orig_decl == decl then
orig_decl = nil
end
if args.notes then
track("notes")
end
local function all_pl_irreg()
track("irreg")
for _, case in ipairs(overridable_cases) do
if rfind(case, "_pl") then
track("irreg/" .. case)
end
end
end
local function track_prefix(prefix)
local function dotrack(suf)
track(prefix .. suf)
end
dotrack(stress)
dotrack(decl)
dotrack(decl .. "/" .. stress)
if orig_decl then
dotrack(orig_decl)
dotrack(orig_decl .. "/" .. stress)
end
for _, hint_type in ipairs(hint_types) do
dotrack(hint_type)
dotrack(decl .. "/" .. hint_type)
if orig_decl then
dotrack(orig_decl .. "/" .. hint_type)
end
end
end
track_prefix("")
if args.reducible then
track("reducible-stem")
track_prefix("reducible-stem/")
end
if rlfind(args.stem, "и́?н$") and (decl == "" or decl == "#") then
track("irregular-in")
end
if args.pltail then
track("pltail")
end
if args.sgtail then
track("sgtail")
end
if args.pltailall then
track("pltailall")
end
if args.sgtailall then
track("sgtailall")
end
if args.pl ~= args.stem then
track("irreg-pl-stem")
track("irreg")
end
if args.alt_gen_pl then
track("alt-gen-pl")
track("irreg")
track("irreg/gen_pl")
end
if args.want_sc1 then
track("want-sc1")
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-и$") or rfind(decl, "-а$") or rfind(decl, "-я$") then
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-ья$") then
track("variant-ья")
all_pl_irreg()
end
if rfind(decl, "%(ишк%)$") then
track("variant-ишко")
end
if rfind(decl, "%(ищ%)$") then
track("variant-ище")
end
if args.jo_special then
track("jo-special")
end
if args.manual then
track("manual")
end
if args.explicit_gender then
track("explicit-gender")
track("explicit-gender/" .. args.explicit_gender)
end
for _, case in ipairs(overridable_cases) do
if args[case .. n] and not args.manual then
track("override")
track("override/" .. case .. n)
track("irreg")
track("irreg/" .. case .. n)
-- questionable use: track_prefix("irreg/" .. case .. "/")
-- questionable use: track_prefix("irreg/" .. case .. n .. "/")
end
if islast and args[case] and not args.manual then
track("override")
track("override/" .. case)
track("irreg")
track("irreg/" .. case)
-- questionable use: track_prefix("irreg/" .. case .. "/")
end
if args[case .. "_tail"] then
track("casenum-tail")
track("casenum-tail/" .. case)
end
if args[case .. "_tailall"] then
track("casenum-tailall")
track("casenum-tailall/" .. case)
end
end
end
local gender_to_full = {m="ပုလ္လိၚ်", f="ဣတ္တိလိၚ်", n="နပုလ္လိၚ်"}
local gender_to_short = {m="masc", f="fem", n="neut"}
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the plural part of speech.
local function insert_category(categories, cat, pos, atbeg)
if enable_categories then
-- local fullcat = "Russian " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(categories, 1, fullcat)
else
table.insert(categories, fullcat)
end
end
end
-- Insert categories into ARGS.CATEGORIES corresponding to the specified
-- stress and declension classes and to the form of the stem (e.g. velar,
-- sibilant, etc.). Also initialize values used to compute the declension
-- heading that describes similar information. N is the number of the
-- word being processed; ISLAST is true if this is the last word.
local function categorize_and_init_heading(stress, decl, args, n, islast)
local function cat_to_list(cat)
if not cat then
return {}
elseif type(cat) == "string" then
return {cat}
else
assert(type(cat) == "table")
return cat
end
end
-- Insert category CAT into the list of categories in ARGS.
-- CAT may be nil, a single string or a list of strings. We call
-- insert_category() on each string. The strings will have "Russian "
-- prepended and "~" replaced with the plural part of speech.
local function insert_cat(cat)
for _, c in ipairs(cat_to_list(cat)) do
insert_category(args.categories, c, args.pos)
end
end
-- "Resolve" the category spec CATSPEC into the sort of category spec
-- accepted by insert_cat(), i.e. nil, a single string or a list of
-- strings. CATSPEC may be any of these or a function, which takes one
-- argument (SUFFIX) and returns another CATSPEC.
local function resolve_cat(catspec, suffix)
if type(catspec) == "function" then
return resolve_cat(catspec(suffix), suffix)
else
return catspec
end
end
-- Check whether an override for nom_sg or nom_pl still contains the
-- normal suffix (which should already have accents removed) in at least
-- one of its entries. If no override then of course we return true.
local function override_matches_suffix(args, case, n, suffix)
assert(suffix == com.remove_accents(suffix))
-- NOTE: It might not be completely correct to pass in args.forms
-- here when n == ""; this is different behavior from
-- handle_overall_forms_and_overrides(). But args.forms is only used
-- to retrieve the dat_sg for handling loc/par, and we're never
-- called with loc or par as the value of CASE, so it doesn't matter.
-- We add an assert to make sure of this.
assert(case ~= "loc" and case ~= "par")
local override = canonicalize_override(args, case, args.forms, n)
if not override then
return true
end
for _, x in ipairs(override) do
local ru, tr = x[1], x[2]
local entry, notes = m_table_tools.separate_notes(ru)
entry = com.remove_accents(m_links.remove_links(entry))
if rlfind(entry, suffix .. "$") then
return true
end
end
return false
end
if args.manual then
return
end
local h = args.heading_info
assert(decl)
local decl_cats = args.old and declensions_old_cat or declensions_cat
local sgdecl, pldecl
local is_slash_decl = rfind(decl, "/")
if is_slash_decl then
local indiv_decls = rsplit(decl, "/")
sgdecl, pldecl = indiv_decls[1], indiv_decls[2]
else
sgdecl, pldecl = decl, decl
end
local sgdc = decl_cats[sgdecl]
local pldc = decl_cats[pldecl]
assert(sgdc)
assert(pldc)
local sghint_types = com.get_stem_trailing_letter_type(
args.stem .. (sgdc.stem_suffix or ""))
-- insert English version of Zaliznyak stem type
if sgdc.decl == "indeclinable" then
insert_cat("indeclinable ~")
insert_if_not(h.stemetc, "indecl")
else
local stem_type =
sgdc.decl == "3rd" and "3rd-declension" or
m_table.contains(sghint_types, "velar") and "velar-stem" or
m_table.contains(sghint_types, "sibilant") and "sibilant-stem" or
m_table.contains(sghint_types, "c") and "ц-stem" or
m_table.contains(sghint_types, "i") and "i-stem" or
m_table.contains(sghint_types, "vowel") and "vowel-stem" or
m_table.contains(sghint_types, "soft-cons") and "vowel-stem" or
m_table.contains(sghint_types, "palatal") and "vowel-stem" or
sgdc.hard == "soft" and "soft-stem" or
"hard-stem"
local short_stem_type = stem_type == "3rd-declension" and "3rd-decl" or stem_type
if sgdc.adj then
-- Don't include gender for pluralia tantum because it's mostly
-- indeterminate (certainly when specified using a plural lemma,
-- which will be usually; technically it's partly or completely
-- determinate in certain old-style adjectives that distinguish
-- masculine from feminine/neuter, but this is too rare a case
-- to worry about)
local gendertext = args.thisn == "p" and "plural-only" or gender_to_full[sgdc.g]
insert_if_not(h.adjectival, "yes")
if args.thisn ~= "p" then
insert_if_not(h.gender, gender_to_short[sgdc.g])
end
if sgdc.possadj then
insert_cat(sgdc.decl .. " possessive " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, sgdc.decl .. " poss")
insert_if_not(h.stress, stress)
elseif stem_type == "soft-stem" or stem_type == "vowel-stem" then
insert_cat(stem_type .. " " .. gendertext .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
else
insert_cat(stem_type .. " " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
else
-- NOTE: There are 8 Zaliznyak-style stem types and 3 genders, but
-- we don't create a category for masculine-form 3rd-declension
-- nouns (there is such a noun, путь, but it mostly behaves
-- like a feminine noun), so there are 23.
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form ~")
-- NOTE: Here we are creating categories for the combination of
-- stem, gender and accent. There are 10 accent patterns and 23
-- combinations of stem and gender, which potentially makes for
-- 10*23 = 230 such categories, which is a lot. Not all such
-- categories should actually exist; there were maybe 75 former
-- declension templates, each of which was essentially categorized
-- by the same three variables, but some of which dealt with
-- ancillary issues like irregular plurals; this amounts to 67
-- actual stem/gender/accent categories, although there are more
-- of them in Zaliznyak (FIXME, how many? See generate_cats.py).
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " ~")
insert_if_not(h.adjectival, "no")
insert_if_not(h.gender, gender_to_short[sgdc.g])
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
insert_cat("~ with accent pattern " .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
local sgsuffix = args.suffixes.nom_sg
if sgsuffix then
assert(#sgsuffix == 1) -- If this ever fails, then implement a loop
sgsuffix = com.remove_accents(sgsuffix[1])
-- If we are plural only or if nom_sg is overridden and has
-- an unusual suffix, then don't create category for sg suffix
if args.thisn == "p" or not override_matches_suffix(args, "nom_sg", n, sgsuffix) or islast and not override_matches_suffix(args, "nom_sg", "", sgsuffix) then
sgsuffix = nil
end
end
local plsuffix = args.suffixes.nom_pl
if plsuffix then
assert(#plsuffix == 1) -- If this ever fails, then implement a loop
plsuffix = com.remove_accents(plsuffix[1])
-- If we are a singulare tantum or if nom_pl is overridden and has
-- an unusual suffix, then don't create category for pl suffix
if args.thisn == "s" or not override_matches_suffix(args, "nom_pl", n, plsuffix) or islast and not override_matches_suffix(args, "nom_pl", "", plsuffix) then
plsuffix = nil
end
end
sgsuffix = sgsuffix and rsub(sgsuffix, "ъ$", "")
plsuffix = plsuffix and rsub(plsuffix, "ъ$", "")
local sgcat = sgsuffix and (resolve_cat(sgdc.singular, sgsuffix) or "ending in " .. (sgsuffix == "" and "a consonant" or (sgdc.suffix and "suffix " or "") .. "-" .. sgsuffix))
local plcat = plsuffix and (resolve_cat(pldc.plural, plsuffix) or "plural -" .. plsuffix)
if sgcat and sgdc.gensg then
for _, cat in ipairs(cat_to_list(sgcat)) do
insert_cat("~ " .. cat)
end
end
if sgcat and plcat and (sgdc.suffix or sgdc.alt_nom_pl or sgdc.irregpl or
is_slash_decl and plsuffix == "-ья") then
for _, scat in ipairs(cat_to_list(sgcat)) do
for _, pcat in ipairs(cat_to_list(plcat)) do
-- insert_cat("~ " .. scat .. " with " .. pcat)
end
end
end
if args.pl ~= args.stem then
-- insert_cat("~ with irregular plural stem")
end
if args.reducible and not sgdc.ignore_reduce then
-- insert_cat("~ with reducible stem")
if args.soft_n then
-- insert_cat("~ with soft final н in reduced stem")
end
insert_if_not(h.reducible, "yes")
else
insert_if_not(h.reducible, "no")
end
if args.alt_gen_pl then
-- insert_cat("~ with alternative genitive plural")
end
if sgdc.adj then
-- insert_cat("adjectival ~")
end
end
local function compute_heading(args)
local headings = {}
local h = args.heading_info
table.insert(headings, args.a == "a" and "anim" or args.a == "i" and
"inan" or "bian")
table.insert(headings, args.nonumber and "uncountable" or
args.n == "s" and "sg-only" or args.n == "p" and "pl-only" or nil)
if #h.gender > 0 then
table.insert(headings, table.concat(h.gender, "/") .. "-form")
end
if #h.stemetc > 0 then
table.insert(headings, table.concat(h.stemetc, "/"))
end
if #h.stress > 0 then
local stresses = {}
for _, stress in ipairs(h.stress) do
table.insert(stresses, (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
table.insert(headings, "accent-" .. table.concat(stresses, "/"))
end
local function handle_bool(boolvals, text, into)
into = into or headings
if m_table.contains(boolvals, "yes") and m_table.contains(boolvals, "no") then
table.insert(into, "[" .. text .. "]")
elseif m_table.contains(boolvals, "yes") then
table.insert(into, text)
end
end
handle_bool(h.adjectival, "adj")
handle_bool(h.reducible, "reduc")
return headings
end
local function compute_overall_heading_categories_and_genders(args)
local hinfo = args.per_word_heading_info
local index = 0
-- First try for non-adjectival, non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") and not m_table.contains(hinfo[i].adjectival, "yes") then
index = i
break
end
end
if index == 0 then
-- Then just non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") then
index = i
break
end
end
end
-- Finally, do anything
if index == 0 then
index = 1
end
-- Compute final heading
local headings = args.per_word_headings[index]
local categories = args.per_word_categories[index]
if args.any_irreg then
table.insert(headings, "irreg")
-- insert_category(categories, "irregular ~", args.pos)
end
for _, case in ipairs(overridable_cases) do
local is_pl = rfind(case, "_pl")
if args.n == "s" and is_pl or args.n == "p" and not is_pl then
-- Don't create singular categories when plural-only or vice-versa
elseif overridable_only_cases_set[case] then
if args.any_overridden[case] then
-- insert_category(categories, "~ with " .. english_case_description(case), args.pos)
end
elseif args.any_irreg_case[case] then
-- insert_category(categories, "~ with irregular " .. english_case_description(case), args.pos)
end
end
local heading = args.manual and "" or "(<span style=\"font-size: smaller;\">[[Appendix:Russian nouns#Declension tables|" .. table.concat(headings, " ") .. "]]</span>)"
args.heading = heading
args.categories = categories
args.genders = args.per_word_genders[index]
end
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Used by do_generate_forms().
local function arg1_is_stress(arg1)
if not arg1 then return false end
for _, arg in ipairs(rsplit(arg1, ",")) do
if not rfind(arg, "^[a-f]'?'?$") then
return false
end
end
return true
end
-- Used by do_generate_forms(), handling a word joiner argument
-- of the form 'join:JOINER'.
local function extract_word_joiner(spec)
word_joiner = rmatch(spec, "^join:(.*)$")
assert(word_joiner)
return com.split_russian_tr(word_joiner, "dopair")
end
local function determine_headword_gender(args, sgdc, gender)
-- If gender unspecified, use normal gender of declension, except when
-- adjectival nouns that are pluralia tantum, where the gender is
-- mostly indeterminate (FIXME, not completely with old-style declensions
-- but we don't handle that currently).
if not gender then
if sgdc.adj and args.thisn == "p" then
gender = nil
else
gender = sgdc.g
end
end
-- Determine headword genders
gender = gender and gender ~= "none" and gender .. "-" or ""
local plsuffix = args.n == "p" and "-p" or ""
local hgens
if args.a == "a" then
hgens = {gender .. "an" .. plsuffix}
elseif args.a == "i" then
hgens = {gender .. "in" .. plsuffix}
elseif args.a == "ai" then
hgens = {gender .. "an" .. plsuffix, gender .. "in" .. plsuffix}
else
hgens = {gender .. "in" .. plsuffix, gender .. "an" .. plsuffix}
end
-- Insert into list of genders
for _, hgen in ipairs(hgens) do
insert_if_not(args.genders, hgen)
end
end
function export.do_generate_forms(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SETS and JOINER, where ARG_SETS
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Gather arguments into a list of ARG_SET objects, containing (potentially)
-- elements 1, 2, 3, 4, corresponding to accent pattern, stem, declension
-- type, pl stem and coming from consecutive numbered parameters. Sets of
-- declension parameters are separated by the word "or".
local arg_sets = {}
-- Find maximum-numbered arg, allowing for holes
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Now gather the arguments.
local offset = 0
local arg_set = {}
for i=1,(max_arg + 1) do
local end_arg_set = false
local end_word = false -- FIXME, is this correct?
local word_joiner
if i == max_arg + 1 then
end_arg_set = true
end_word = true
word_joiner = {""}
elseif args[i] == "_" then
end_arg_set = true
end_word = true
word_joiner = {" "}
elseif args[i] == "-" then
end_arg_set = true
end_word = true
word_joiner = {"-"}
elseif args[i] and rfind(args[i], "^join:") then
end_arg_set = true
end_word = true
word_joiner = extract_word_joiner(args[i])
elseif args[i] == "or" then
end_arg_set = true
end
if end_arg_set then
table.insert(arg_sets, arg_set)
arg_set = {}
offset = i
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
else
-- If the first argument isn't stress, that means all arguments
-- have been shifted to the left one. We want to shift them
-- back to the right one, so we change the offset so that we
-- get the same effect of skipping a slot in the arg set.
if i - offset == 1 and not arg1_is_stress(args[i]) then
offset = offset - 1
end
if i - offset > 4 then
error("Too many arguments for argument set: arg " .. i .. " = " .. (args[i] or "(blank)"))
end
arg_set[i - offset] = args[i]
end
end
return generate_forms_1(args, per_word_info)
end
function export.do_generate_forms_multi(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SET and JOINER, where ARG_SET
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Find maximum-numbered arg, allowing for holes (FIXME: Is this needed
-- here? Will there be holes?)
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Gather arguments into a list of ARG_SET objects, containing
-- (potentially) elements 1, 2, 3, corresponding to accent pattern,
-- lemma+declension spec, pl stem, exactly as with do_generate_forms()
-- and {{ru-noun-table}} except that the values come from a single argument
-- of the form ACCENTPATTERN:LEMMADECL:PL where all but LEMMADECL may (and
-- probably will be) omitted and LEMMADECL may be of the following forms:
-- LEMMA (for a noun with empty decl spec),
-- LEMMADECL (for a noun with non-empty decl spec beginning with a
-- *, left paren or semicolon),
-- LEMMA^DECL (for a noun with non-empty decl spec),
-- LEMMA$ (for an indeclinable word)
-- LEMMA+ (for an adjective with auto-detected decl class)
-- LEMMA+DECL (for an adjective with explicit decl class)
-- Sets of parameters for the same word are separated by the word "or".
local arg_sets = {}
local continue_arg_sets = true
for i=1,(max_arg + 1) do
local end_word = false
local word_joiner
local process_arg = false
if i == max_arg + 1 then
end_word = true
word_joiner = {""}
elseif args[i] == "-" then
end_word = true
word_joiner = {"-"}
continue_arg_sets = true
elseif rfind(args[i], "^join:") then
end_word = true
word_joiner = extract_word_joiner(args[i])
continue_arg_sets = true
elseif args[i] == "or" then
continue_arg_sets = true
else
if continue_arg_sets then
continue_arg_sets = false
else
end_word = true
word_joiner = {" "}
end
process_arg = true
end
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
if process_arg then
local vals = rsplit(args[i], ":")
if #vals > 3 then
error("Can't specify more than 3 colon-separated params of param set: " .. args[i])
end
local arg_set = {}
if arg1_is_stress(vals[1]) then
arg_set[1] = vals[1]
arg_set[2] = vals[2]
arg_set[4] = vals[3]
else
arg_set[2] = vals[1]
arg_set[4] = vals[2]
end
-- recognize indeclinable
local indecl_stem = rmatch(arg_set[2], "^(.-)%$$")
if indecl_stem then
arg_set[2] = indecl_stem
arg_set[3] = "$"
else
-- recognize adjective
local adj_stem, adj_type = rmatch(arg_set[2], "^(.*)(%+.*)$")
if adj_stem then
arg_set[2] = adj_stem
arg_set[3] = adj_type
else
-- recognize noun with ^
local noun_stem, noun_type = rmatch(arg_set[2], "^(.*)%^(.*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- recognize noun without ^ but with decl spec
noun_stem, noun_type = rmatch(arg_set[2], "^(..-)([;*(].*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- noun without ^ or decl spec; nothing to do
end
end
end
end
table.insert(arg_sets, arg_set)
end
end
return generate_forms_1(args, per_word_info)
end
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence.
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence,
-- as well as show_z() for template {{ru-decl-noun-z}}, which has a
-- subset of the functionality of the other two.
generate_forms_1 = function(args, per_word_info)
local orig_args
if test_new_ru_noun_module then
orig_args = mw.clone(args)
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local old = args.old
local function verify_animacy_value(val)
if not val then return nil end
if val == "a" or val == "an" or val == "anim" then
return "a"
elseif val == "i" or val == "in" or val == "inan" then
return "i"
elseif val == "b" or val == "bi" or val == "both" or val == "ai" then
return "ai"
elseif val == "ia" then
return "ia"
end
error("Animacy value " .. val .. " should be empty or a/an/anim (animate), i/in/inan (inanimate), b/bi/both/ai (bianimate, listing animate first), or ia (bianimate, listing inanimate first)")
return nil
end
local function verify_number_value(val, allow_none)
if not val then return nil end
local short = usub(val, 1, 1)
if short == "s" or short == "p" or short == "b" or (allow_none and short == "n" or false) then
return short
end
if allow_none then
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), 'b' (both) or 'n' (none)")
else
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), or 'b' (both)")
end
return nil
end
-- Verify and canonicalize animacy, number, prefix, suffix
assert(#per_word_info >= 1)
for i=1,#per_word_info do
args["a" .. i] = verify_animacy_value(args["a" .. i])
args["n" .. i] = verify_number_value(args["n" .. i])
args["prefix" .. i] = com.split_russian_tr(args["prefix" .. i] or "", "dopair")
args["suffix" .. i] = com.split_russian_tr(args["suffix" .. i] or "", "dopair")
end
args.a = verify_animacy_value(args.a) or "i"
-- args.ndef, if set, is the default value for args.n; if unset, it defaults
-- to "both". It is set to "singular" in ru-proper noun+. We store the value
-- of args.n in args.orign before defaulting to args.ndef because we may
-- change it to plural-only later on if it was unspecified (this happens if
-- an individual word's lemma is plural), and to determine whether it was
-- unspecified, we need the original value before defaulting.
args.n = verify_number_value(args.n, "allow none")
-- treat n=none like n=sg but set a flag so "singular" isn't displayed
if args.n == "n" then
args.n = "s"
args.nonumber = true
end
args.ndef = verify_number_value(args.ndef)
args.orign = args.n
args.n = args.n or args.ndef
args.prefix = com.split_russian_tr(args.prefix or "", "dopair")
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
-- Attach overall prefix to first per-word prefix, similarly for suffix
args.prefix1 = com.concat_paired_russian_tr(args.prefix, args.prefix1)
args["suffix" .. #per_word_info] = com.concat_paired_russian_tr(
args["suffix" .. #per_word_info], args.suffix)
-- Initialize non-word-specific arguments.
--
-- The following is a list of WORD_INFO items, one per word, each of
-- which is a two element list of WORD_FORMS (a table listing the forms for
-- each case) and JOINER (a string, indicating how to join the word with
-- the next one).
args.per_word_info = {}
-- List of HEADING_INFO items, one per word, containing the raw material
-- used to generate the header. Initialized from 'args.heading_info',
-- which is initialized in categorize_and_init_heading().
args.per_word_heading_info = {}
-- List of CATEGORIES items, one per word, containing the categories
-- used to initialize the page categories. Initialized from
-- 'args.categories', which is initialized in categorize_and_init_heading().
args.per_word_categories = {}
-- List of HEADINGS items, one per word, containing the actual words that
-- go into the header if we were to use that word to construct the header.
-- Comes from compute_heading(). We use this to generate the actual header
-- string, which goes into 'args.heading' at the end (done in
-- compute_overall_heading_categories_and_genders()).
args.per_word_headings = {}
-- List of GENDERS items, one per word, containing the headword genders
-- for each word (where "headword gender" is in the format used in
-- headwords and actually includes animacy and number as well, e.g.
-- 'm-in' or 'f-an-p'). We end up selecting one such item and putting
-- it into 'args.genders' at the end
-- (in compute_overall_heading_categories_and_genders()).
args.per_word_genders = {}
args.any_overridden = {}
args.any_non_nil = {}
args.any_irreg = false
args.any_irreg_case = {}
local function insert_cat(cat)
insert_category(args.categories, cat, args.pos)
end
args.internal_notes = {}
local decl_sufs = old and declensions_old or declensions
local decl_cats = old and declensions_old_cat or declensions_cat
local intable = old and internal_notes_table_old or internal_notes_table
-- Default lemma defaults to previous lemma, first one to page name.
-- FIXME: With multiple words, we should probably split the page name
-- on spaces and default each word in turn
local default_lemma
local all_stresses_seen
-- Made into a function to avoid having to indent a lot of code.
-- Process a single arg set of a single word. This inserts the forms
-- for the word into args.forms and sets categories and tracking pages.
local function do_arg_set(arg_set, n, islast)
local stress_arg = arg_set[1]
local decl = arg_set[3] or ""
local pl, pltr
if arg_set[4] then
pl, pltr = com.split_russian_tr(arg_set[4])
end
-- Extract special markers from declension class.
if decl == "manual" then
decl = "$"
args.manual = true
if #per_word_info > 1 or #per_word_info[1][1] > 1 then
error("Can't specify multiple words or argument sets when manual")
end
if pl then
error("Can't specify optional stem parameters when manual")
end
end
decl, args.jo_special = rsubb(decl, "([^/%a])ё$", "%1")
if not args.jo_special then
decl, args.jo_special = rsubb(decl, "([^/%a])ё([^/%a])", "%1%2")
end
decl, args.want_sc1 = rsubb(decl, "%(1%)", "")
decl, args.alt_gen_pl = rsubb(decl, "%(2%)", "")
decl, args.reducible = rsubb(decl, "%*", "")
decl, args.soft_n = rsubb(decl, "%(нь%)", "")
decl = rsub(decl, ";", "")
-- Get the lemma.
local lemma = args.manual and "-" or arg_set[2] or default_lemma
if not lemma then
error("Lemma in first argument set must be specified")
end
default_lemma = lemma
local lemmatr
lemma, lemmatr = com.split_russian_tr(lemma)
-- If we're conjugating a suffix, insert a pseudoconsonant at the beginning
-- of all forms, so they get conjugated as if ending in a consonant.
-- We remove the pseudoconsonant later.
local is_suffix = lemma ~= "-" and rfind(lemma, "^%-")
args.any_suffix = args.any_suffix or is_suffix
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or is_suffix and PSEUDOCONS
if asif_prefix then
lemma = rsub(lemma, "^%-", "-" .. asif_prefix)
if lemmatr then
lemmatr = rsub(lemmatr, "^%-", "-" .. com.translit(asif_prefix))
end
end
args.thisa = args["a" .. n] or args.a
args.thisn = args["n" .. n] or args.n
-- Check for explicit allow-unaccented indication.
local allow_unaccented
lemma, allow_unaccented = rsubb(lemma, "^%*", "")
args.allow_unaccented = args.allow_unaccented or allow_unaccented
if args.allow_unaccented then
track("allow-unaccented")
end
args.orig_lemma = lemma
lemma = m_links.remove_links(lemma)
args.lemma_no_links = lemma
args.lemmatr = lemmatr
if args.lemma then
-- Explicit lemma given.
args.explicit_lemma, args.explicit_lemmatr = com.split_russian_tr(args.lemma)
end
-- Treat suffixes without an accent, and suffixes with an accent on the
-- initial hyphen, as if they were preceded with a *, which overrides
-- all the logic that normally (a) normalizes the accent, and (b)
-- complains about multisyllabic words without an accent. Don't do this
-- if lemma is just -, which is used specially in manual declension
-- tables (e.g. сто, три).
if lemma ~= "-" and (rfind(lemma, "^%-" .. AC) or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
-- Convert lemma and decl arg into stem and canonicalized decl.
-- This will autodetect the declension from the lemma if an explicit
-- decl isn't given.
local stem, tr, gender, was_accented, was_plural, was_autodetected
if rfind(decl, "^%+") then
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
detect_adj_type(lemma, lemmatr, decl, old)
else
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
determine_decl(lemma, lemmatr, decl, args)
end
if was_plural then
args.n = args.orign or "p"
args.thisn = args["n" .. n] or args.n
elseif decl ~= "$" then
args.thisn = args.thisn or "b"
end
args.explicit_gender = gender
-- If allow-unaccented not given, maybe check for missing accents.
if not args.allow_unaccented and not stress_arg and was_autodetected and com.needs_accents(lemma) then
-- If user gave the full word and expects us to determine the
-- declension and stress, the word should have an accent on the
-- stem or ending. We have a separate check farther below for
-- an accent on a multisyllabic stem, after stripping off any
-- ending; but this way we get an error if the user e.g. writes
-- "гора" without an accent rather than assuming it's stem
-- stressed, as would otherwise happen.
error("Lemma must have an accent in it: " .. lemma)
end
-- If stress not given, auto-determine; else validate/canonicalize
-- stress arg, override in certain cases and convert to list.
if not stress_arg then
stress_arg = {detect_stress_pattern(stem, decl, decl_cats, args.reducible, was_plural, was_accented)}
else
stress_arg = rsplit(stress_arg, ",")
for i=1,#stress_arg do
local stress = stress_arg[i]
stress = override_stress_pattern(decl, stress)
if not stress_patterns[stress] then
error("Unrecognized accent pattern " .. stress)
end
stress_arg[i] = stress
end
end
-- parse slash decl to list
local sub_decls
if rfind(decl, "/") then
track("mixed-decl")
insert_cat("~ with mixed declension")
local indiv_decls = rsplit(decl, "/")
-- Should have been caught in canonicalize_decl()
assert(#indiv_decls == 2)
sub_decls = {{indiv_decls[1], "sg"}, {indiv_decls[2], "pl"}}
else
sub_decls = {{decl}}
end
-- Get singular declension and corresponding category.
local sgdecl = sub_decls[1][1]
local sgdc = decl_cats[sgdecl]
assert(sgdc)
-- Compute headword gender(s). We base it off the singular declension
-- if we have a slash declension -- it's the best we can do.
determine_headword_gender(args, sgdc, gender)
local original_stem, original_tr = stem, tr
local original_pl, original_pltr = pl, pltr
-- Loop over accent patterns in case more than one given.
for _, stress in ipairs(stress_arg) do
args.suffixes = {}
stem, tr = original_stem, original_tr
local bare, baretr
local stem_for_bare, tr_for_bare
pl, pltr = original_pl, original_pltr
insert_if_not(all_stresses_seen, stress)
local stem_was_unstressed = com.is_unstressed(stem)
-- If special case ;ё was given and stem is unstressed,
-- add ё to the stem now; but don't let this interfere with
-- restressing, to handle cases like железа́ with gen pl желёз
-- but nom pl же́лезы.
if stem_was_unstressed and args.jo_special then
-- Beware, Cyrillic еЕ in first rsub, Latin eE in second
local new_stem = rsub(stem, "([еЕ])([^еЕ]*)$",
function(e, rest)
return (e == "Е" and "Ё" or "ё") .. rest
end
)
if stem == new_stem then
error("No е in stem to replace with ё")
end
stem = new_stem
if tr then
local subbed
-- e after j -> o, e not after j -> jo; don't just convert e -> jo
-- and then map jjo -> jo because we want to preserve double j
tr, subbed = rsubb(tr, "([jJ])([eE])([^eE]*)$",
function(j, e, rest)
return j .. (e == "E" and "O" or "o") .. AC .. rest
end
)
if not subbed then
tr = rsub(tr, "([eE])([^eE]*)$",
function(e, rest)
return (e == "E" and "Jo" or "jo") .. AC .. rest
end
)
end
tr = com.j_correction(tr)
end
-- This is used to handle железа́ with gen pl желёз and nom pl
-- же́лезы. We have two stressed stems, one for the gen pl and
-- one for the remaining pl cases, and the variable 'stem' can
-- handle only one, so we put the second (gen pl) stem in
-- stem_for_bare, which goes into the value of 'bare' (used
-- only for gen pl here).
stem_for_bare, tr_for_bare = stem, tr
end
-- Maybe add stress to the stem, depending on whether the
-- stem was unstressed and the stress pattern. Stem pattern f
-- and variants call for initial stress (голова́ -> го́ловы);
-- stem pattern d and variants call for stem-final stress
-- (сапожо́к -> сапо́жки). Stem patterns b and b' apparently
-- call for stem-final stress as well but it's unlikely to
-- make much of a difference (pattern b' only occurs in 3rd-decl
-- feminines, which should already have stress in the stem,
-- and the only place pattern b gets stem stress is in bare
-- forms, i.e. nom sg and/or gen pl depending on the decl type,
-- and nom sg stress should already be in the lemma while
-- gen pl stress is handled by a different ending-stressing
-- mechanism in attach_unstressed(); however, the user is
-- free to leave a masc or 3rd-decl fem lemma completely
-- unstressed with pattern b, and then the stem-final stress
-- *will* make a difference).
local function restress_stem(stem, tr, stress, stem_unstressed)
-- If the user has indicated they purposely are leaving the
-- word unstressed by putting a * at the beginning of the main
-- stem, leave it unstressed. This might indicate lack of
-- knowledge of the stress or a truly unaccented word
-- (e.g. an unaccented suffix).
if args.allow_unaccented then
return stem, tr
end
if tr and com.is_unstressed(stem) ~= com.is_unstressed(tr) then
error("Stem " .. stem .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(stem) then
stem, tr = com.make_ending_stressed(stem, tr)
-- For those patterns that are ending-stressed in the singular
-- nominative (and hence are likely to be expressed without an
-- accent on the stem) it's safe to put a particular accent on
-- the stem depending on the stress type. Otherwise, give an
-- error if no accent.
elseif stem_unstressed then
if rfind(stress, "^f") then
stem, tr = com.make_beginning_stressed(stem, tr)
elseif (rfind(stress, "^[bd]") or
args.thisn == "p" and ending_stressed_pl_patterns[stress]) then
stem, tr = com.make_ending_stressed(stem, tr)
elseif com.needs_accents(stem) then
error("Stem " .. stem .. " requires an accent")
end
end
return stem, tr
end
stem, tr = restress_stem(stem, tr, stress, stem_was_unstressed)
-- Leave pl unaccented if user wants this; see restress_stem().
if pl and not args.allow_unaccented then
if pltr and com.is_unstressed(pl) ~= com.is_unstressed(pltr) then
error("Plural stem " .. pl .. " and translit " .. pltr .. " must have same accent pattern")
end
if com.is_monosyllabic(pl) then
pl, pltr = com.make_ending_stressed(pl, pltr)
end
-- I think this is safe.
if com.needs_accents(pl) then
if ending_stressed_pl_patterns[stress] then
pl, pltr = com.make_ending_stressed(pl, pltr)
elseif not args.allow_unaccented then
error("Plural stem " .. pl .. " requires an accent")
end
end
end
local resolved_bare, resolved_baretr
-- Handle (de)reducibles
-- FIXME! We are dereducing based on the singular declension.
-- In a slash declension things can get weird and we don't
-- handle that. We are also computing the bare value from the
-- singular stem, and again things can get weird with a plural
-- stem. Note that we don't compute a bare value unless we have
-- to (either (de)reducible or stress pattern f/f'/f'' combined
-- with ё special case); the remaining times we generate the bare
-- value directly from the plural stem.
if args.reducible and not sgdc.ignore_reduce then
-- Zaliznyak treats all nouns in -ье and -ья as being
-- reducible. We handle this automatically and don't require
-- the user to specify this, but ignore it if so for
-- compatibility.
if is_reducible(sgdc) then
-- If we derived the stem from a nom pl form, then
-- it's already reduced, and we need to dereduce it to
-- get a bare form; otherwise the stem comes from the
-- nom sg and we need to reduce it to get the real stem.
if was_plural then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
resolved_bare, resolved_baretr = stem, tr
stem, tr = export.reduce_nom_sg_stem(stem, tr,
sgdecl, args.soft_n, "error")
-- Stem will be unstressed if stress was on elided
-- vowel; restress stem the way we did above. (This is
-- needed in at least one word, сапожо́к 3*d(2), with
-- plural stem probably сапо́жк- and gen pl probably
-- сапо́жек.)
stem, tr = restress_stem(stem, tr, stress,
com.is_unstressed(stem))
if stress ~= "a" and stress ~= "b" and args.alt_gen_pl and not pl then
-- Nouns like рожо́к, глазо́к of type 3*d(2) have
-- gen pl's ро́жек, гла́зок; to handle this,
-- dereduce the reduced stem and store in a
-- special place.
args.gen_pl_bare, args.gen_pl_baretr =
export.dereduce_nom_sg_stem(stem, tr,
sgdc, stress, old, "error")
end
end
elseif is_dereducible(sgdc) then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
error("Declension class " .. sgdecl .. " not (de)reducible")
end
elseif stem_for_bare and stem ~= stem_for_bare then
resolved_bare, resolved_baretr =
add_bare_suffix(stem_for_bare, tr_for_bare, old, sgdc, false)
end
-- Leave unaccented if user wants this; see restress_stem().
-- FIXME, we no longer allow the user to specify the bare value
-- so it's unclear if this is needed any more.
if resolved_bare and not args.allow_unaccented then
if resolved_baretr and com.is_unstressed(resolved_bare) ~= com.is_unstressed(resolved_baretr) then
error("Resolved bare stem " .. resolved_bare .. " and translit " .. resolved_baretr .. " must have same accent pattern")
end
if com.is_monosyllabic(resolved_bare) then
resolved_bare, resolved_baretr =
com.make_ending_stressed(resolved_bare, resolved_baretr)
else
if com.needs_accents(resolved_bare) then
error("Resolved bare stem " .. resolved_bare .. " requires an accent")
end
end
end
args.stem, args.stemtr = stem, tr
args.bare, args.baretr = resolved_bare, resolved_baretr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, tr)
if pl then
args.pl, args.pltr = pl, pltr
else
args.pl, args.pltr = stem, tr
end
args.upl, args.upltr = com.make_unstressed_once(args.pl, args.pltr)
-- Special hack for любо́вь and other reducible 3rd-fem nouns,
-- which have the full stem in the ins sg
args.ins_sg_stem = sgdecl == "ь-f" and args.reducible and resolved_bare
args.ins_sg_tr = sgdecl == "ь-f" and args.reducible and resolved_baretr
-- Loop over declension classes (we may have two of them, one for
-- singular and one for plural, in the case of a mixed declension
-- class of the form SGDECL/PLDECL).
for _,decl_spec in ipairs(sub_decls) do
local orig_decl = decl_spec[1]
local number = decl_spec[2]
local real_decl =
determine_stress_variant(orig_decl, stress)
real_decl = determine_stem_variant(real_decl,
number == "pl" and args.pl or args.stem)
-- sanity checking; errors should have been caught in
-- canonicalize_decl()
assert(decl_cats[real_decl], "real_decl " .. real_decl .. " nonexistent")
assert(decl_sufs[real_decl], "real_decl " .. real_decl .. " nonexistent")
tracking_code(stress, orig_decl, real_decl, args, n, islast)
do_stress_pattern(stress, args, real_decl, number, n, islast)
-- handle internal notes
local internal_note = intable[real_decl]
if internal_note then
insert_if_not(args.internal_notes, internal_note)
end
end
categorize_and_init_heading(stress, decl, args, n, islast)
end
end
local n = 0
for _, word_info in ipairs(per_word_info) do
n = n + 1
local islast = n == #per_word_info
local arg_sets, joiner = word_info[1], word_info[2]
args.forms = {}
args.heading_info = {animacy={}, number={}, gender={}, stress={},
stemetc={}, adjectival={}, reducible={}}
args.categories = {}
args.genders = {}
args.this_any_non_nil = {}
args.any_suffix = false
if #arg_sets > 1 then
track("multiple-arg-sets")
-- insert_cat("~ with multiple argument sets")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
default_lemma = pagename
all_stresses_seen = {}
-- Loop over all arg sets.
for _, arg_set in ipairs(arg_sets) do
do_arg_set(arg_set, n, islast)
end
if #all_stresses_seen > 1 then
track("multiple-accent-patterns")
-- insert_cat("~ with multiple accent patterns")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
table.insert(args.per_word_heading_info, args.heading_info)
table.insert(args.per_word_categories, args.categories)
local headings = compute_heading(args)
table.insert(args.per_word_headings, headings)
table.insert(args.per_word_genders, args.genders)
handle_forms_and_overrides(args, n, islast)
if args.any_suffix then
-- If we're conjugating a suffix, remove the pseudoconsonant or asif_prefix
-- that we previously inserted at the beginning.
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or PSEUDOCONS
local asif_prefix_tr = com.translit(asif_prefix)
for _, case in ipairs(all_cases) do
if args.forms[case] then
local newforms = {}
for _, form in ipairs(args.forms[case]) do
local formru = form[1]
local formtr = form[2]
formru = rsub(formru, "^%-" .. asif_prefix, "-")
if formtr then
formtr = rsub(formtr, "^%-" .. asif_prefix_tr, "-")
end
if formru == "-" then
-- if no ending, insert "(no suffix)".
table.insert(newforms, {"(no suffix)"})
else
table.insert(newforms, {formru, formtr})
end
end
args.forms[case] = newforms
end
end
end
table.insert(args.per_word_info, {args.forms, joiner})
end
handle_overall_forms_and_overrides(args)
compute_overall_heading_categories_and_genders(args)
for _, case in ipairs(all_cases) do
if args[case] then
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
ruentry = m_links.remove_links(ruentry)
if rfind(ulower(ruentry), latin_text_class) then
--error("Found Latin text " .. ruentry .. " in case " .. case)
track("latin-text")
track("latin-text/" .. case)
end
end
end
end
-- Test code to compare existing module to new one.
if test_new_ru_noun_module then
local m_new_ru_noun = require("Module:User:Benwing2/ru-noun")
local newargs = m_new_ru_noun.do_generate_forms(orig_args, old)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
local is_pl = rfind(case, "_pl")
if args.thisn == "s" and is_pl or args.thisn == "p" and not is_pl then
-- Don't need to check cases that won't be displayed.
elseif not m_table.deepEquals(arg, newarg) then
local monosyl_accent_diff = false
-- Differences only in monosyllabic accents. Enable if we
-- change the algorithm for these.
--if arg and newarg and #arg == 1 and #newarg == 1 then
-- local ru1, tr1 = arg[1][1], arg[1][2]
-- local ru2, tr2 = newarg[1][1], newarg[1][2]
-- if com.is_monosyllabic(ru1) and com.is_monosyllabic(ru2) then
-- ru1, tr1 = com.remove_accents(ru1, tr1)
-- ru2, tr2 = com.remove_accents(ru2, tr2)
-- if ru1 == ru2 and tr1 == tr2 then
-- monosyl_accent_diff = true
-- end
-- end
--end
if monosyl_accent_diff then
track("monosyl-accent-diff")
difdecl = true
else
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
end
if not difdecl then track("same-decl") end
end
return args
end
-- Implementation of main entry point
local function do_show(frame, old)
local args = clone_args(frame)
local args = export.do_generate_forms(args, old)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- Implementation of new entry point, esp. for multiple words
local function do_show_multi(frame)
local args = clone_args(frame)
local args = export.do_generate_forms_multi(args)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The new entry point, esp. for multiple words (but works fine for
-- single words).
function export.show_multi(frame)
return do_show_multi(frame)
end
local function get_form(forms, preserve_links, raw)
local canon_forms = {}
for _, form in ipairs(forms) do
if raw then
local ru, tr = form[1], form[2]
ru = rsub(ru, "|", "<!>")
if tr then
tr = rsub(tr, "|", "<!>")
end
insert_if_not(canon_forms, {ru, tr})
else
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
-- Skip hypothetical forms (but include in the raw versions)
if not rfind(runotes, HYPMARKER) then
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
end
if not preserve_links then
ruentry = m_links.remove_links(ruentry)
end
ruentry = rsub(ruentry, "|", "<!>")
if trentry then
trentry = rsub(trentry, "|", "<!>")
end
insert_if_not(canon_forms, {ruentry, trentry})
end
end
end
return com.concat_forms(canon_forms)
end
local function case_will_be_displayed(args, case)
local ispl = rfind(case, "_pl")
local caseok = true
if args.n == "p" then
caseok = ispl
elseif args.n == "s" then
caseok = not ispl
end
for _, override_case in ipairs(overridable_only_cases) do
if case == override_case and not args.any_overridden[override_case] then
caseok = false
break
end
end
if args.a == "a" or args.a == "i" then
if rfind(case, "_[ai]n") then
caseok = false
end
else -- bianimate
-- don't include inanimate/animate variants if combined variant exists
-- (typically because inanimate/animate variants are the same);
-- FIXME: This could conceivably be different from how the display
-- code works, which just checks that the inanimate/animate variants
-- are the same when deciding whether to display them, in particular
-- if there is an override. Here we are following the algorithm of
-- handle_overall_forms_and_overrides().
if (case == "acc_sg_in" or case == "acc_sg_an") and args.acc_sg or
(case == "acc_pl_in" or case == "acc_pl_an") and args.acc_pl then
caseok = false
end
end
if not args[case] then
caseok = false
end
return caseok
end
local function concat_case_args(args, do_all, raw)
local ins_text = {}
for _, case in ipairs(do_all and all_cases or overridable_cases) do
if case_will_be_displayed(args, case) then
local forms = get_form(args[case], rfind(case, "_linked"), raw)
if forms ~= "" then
table.insert(ins_text, case .. (raw and "_raw" or "") .. "=" ..
forms)
end
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-noun-forms' to generate all noun forms.
-- This returns a single string, with | separating arguments and named
-- arguments of the form NAME=VALUE.
function export.generate_forms(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
return concat_case_args(args)
end
-- The entry point to generate multiple sets of noun forms. This is a hack
-- to speed up calling from a bot, where we often want to compare old and new
-- argument results to make sure they're the same. Each set of arguments is
-- jammed together into a single argument with individual values separated by
-- <!>; named arguments are of the form NAME<->VALUE. The return value for
-- each set of arguments is as in export.generate_forms(), and the return
-- values are concatenated with <!> separating them. NOTE: This will fail if
-- the exact sequences <!> or <-> happen to occur in values (which is unlikely,
-- esp. as we don't even use the characters <, ! or > for anything) and aren't
-- HTML-escaped.
function export.generate_multi_forms(frame)
local retvals = {}
for _, argset in ipairs(frame.args) do
local args = {}
local i = 0
local argvals = rsplit(argset, "<!>")
for _, argval in ipairs(argvals) do
local split_arg = rsplit(argval, "<%->")
if #split_arg == 1 then
i = i + 1
args[i] = ine(split_arg[1])
else
assert(#split_arg == 2)
args[split_arg[1]] = ine(split_arg[2])
end
end
args = export.do_generate_forms(args, false)
table.insert(retvals, concat_case_args(args))
end
return table.concat(retvals, "<!>")
end
-- The entry point for 'ru-noun-form' to generate a particular noun form.
function export.generate_form(frame)
local args = clone_args(frame)
if not args.form then
error("Must specify desired form using form=")
end
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
local args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
-- The entry point for generating arguments of various sorts, including
-- the case forms, gender, number and animacy.
function export.generate_args(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
local retargs = {}
table.insert(retargs, concat_case_args(args, "doall"))
table.insert(retargs, concat_case_args(args, "doall", "raw"))
table.insert(retargs, "g=" .. table.concat(args.genders, ","))
-- The following is correct even with ndef because if ndef is
-- set we will set it in args.n.
table.insert(retargs, "n=" .. (args.n or "b"))
table.insert(retargs, "a=" .. (args.a or "i"))
return table.concat(retargs, "|")
end
-- The entry point for compatibility with {{ru-decl-noun-z}}.
function export.show_z(frame)
local args = clone_args(frame)
local stem = args[1]
local stress = args[2]
local specific = args[4] or ""
-- Parse gender/animacy spec
local gender, anim = rmatch(args[3], "^([mfn])-([a-z]+)")
if not gender then
error("Unrecognized gender/anim spec " .. args[3])
end
if anim ~= "an" and anim ~= "in" then anim = "both" end
args.a = anim
-- Handle specific
specific = rsub(specific, "ё", ";ё")
-- Compute decl; special case for семьянин (perhaps not necessary)
local decl = com.make_unstressed_once(stem) == "семьянин" and "#" .. specific or gender .. specific
-- Handle overrides
args.pre_sg = args.prp_sg
args.pre_pl = args.prp_pl
args.notes = args.note
if args.par then
args.par = "+"
end
if args.loc then
if args.loc == "в" then
args.loc = "в +"
elseif args.loc == "на" then
args.loc = "на +"
else
args.loc = "в +,на +"
end
end
local arg_set = {}
table.insert(arg_set, stress)
table.insert(arg_set, stem)
table.insert(arg_set, decl)
local per_word_info = {{{arg_set}, ""}}
return generate_forms_1(args, per_word_info)
end
--------------------------------------------------------------------------
-- Autodetection and lemma munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the stem and the ending. GENDER must be present with -ь and plural
-- stems, and is otherwise ignored. Return up to three values: The stem
-- (lemma minus ending), the singular lemma ending, and if the lemma was
-- plural, the plural lemma ending. If the lemma was singular, the singular
-- lemma ending will contain any user-given accents; likewise, if the
-- lemma was plural, the plural ending will contain such accents.
-- VARIANT comes from the declension spec and controls certain declension
-- variants.
local function detect_lemma_type(lemma, tr, gender, args, variant)
local base, ending = rmatch(lemma, "^(.*)([еЕ]" .. AC .. ")$") -- accented
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([еЕ])$") -- unaccented
if base then
if variant == "-ище" and not rfind(lemma, "[щЩ][еЕ]$") then
error("With declension variant -ище, lemma should end in -ще: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), variant == "-ище" and "(ищ)е-и" or "о"
end
if variant == "-ишко" then
base, ending = rmatch(lemma, "^(.*[шШ][кК])([оО])$") -- unaccented
if not base then
error("With declension variant -ишко, lemma should end in -шко: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), "(ишк)о-и"
end
if variant == "-ин" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$") -- maybe accented
if not base then
error("With declension variant -ин, lemma should end in -ин(ъ): " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
-- Now autodetect -ин; only animate and in -анин/-янин
base, ending = rmatch(lemma, "^(.*[аАяЯ][" .. AC .. GR .. "]?[нН])([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$")
-- Need to check the animacy to avoid nouns like маиганин, цианин,
-- меланин, соланин, etc.
if base and args.thisa == "a" then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([мМ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
--recognize plural endings
if gender == "n" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
-- Don't do this; о/-ья is too rare
-- error("Ambiguous plural lemma " .. lemma .. " in -ья, singular could be -о or -ье/-ьё; specify the singular")
return base, com.strip_tr_ending(tr, ending), "ье", ending
end
base, ending = rmatch(lemma, "^(.*)([аяАЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), rfind(ending, "[аА]") and "о" or "е", ending
end
base, ending = rmatch(lemma, "^(.*)([ыиЫИ][" .. AC .. GR .. "]?)$")
if base then
if rfind(ending, "[ыЫ]") or rfind(base, "[" .. com.sib .. com.velar .. "]$") then
return base, com.strip_tr_ending(tr, ending), "о-и", ending
else
-- FIXME, should we return a slash declension?
error("No neuter declension е-и available; use a slash declension")
end
end
end
if gender == "f" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ья", ending
end
end
-- Recognize masculines with irregular plurals, but only if the user
-- either explicitly specified that this noun is plural (n=p) or
-- specifically requested the irregular plural. This is necessary
-- because some masculine nouns have feminine endings, which look
-- like irregular plurals.
if gender == "m" then
if args.thisn == "p" or variant == "-ья" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-ья" or "-ья"), ending
end
end
if args.thisn == "p" or args.want_sc1 then
base, ending = rmatch(lemma, "^(.*)([аА][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-а" or "-а"), ending
end
base, ending = rmatch(lemma, "^(.*)([яЯ][" .. AC .. GR .. "]?)$")
if base then
if rfind(base, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return base, com.strip_tr_ending(tr, ending), "й-я", ending
else
return base, com.strip_tr_ending(tr, ending), "ь-я", ending
end
end
end
end
if gender == "m" or gender == "f" then
base, ending = rmatch(lemma, "^(.*[" .. com.sib .. com.velar .. "])([иИ][" .. AC .. GR .. "]?)$")
if not base then
base, ending = rmatch(lemma, "^(.*)([ыЫ][" .. AC .. GR .. "]?)$")
end
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and (args.old and "ъ" or "") or "а", ending
end
base, ending = rmatch(lemma, "^(.*[" .. com.vowel .. "й][" .. AC .. GR .. "]?)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "й" or "я", ending
end
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "ь-m" or "я", ending
end
end
if gender == "3f" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ь-f", ending
end
end
-- end of recognize-plurals code
base, ending = rmatch(lemma, "^(.*)([ьЬ][яеёЯЕЁ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([йаяеоёъЙАЯЕОЁЪ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ьЬ])$")
if base then
if gender == "m" or gender == "f" then
return base, com.strip_tr_ending(tr, ending), "ь-" .. gender
elseif gender == "3f" then
return base, com.strip_tr_ending(tr, ending), "ь-f"
else
error("Need to specify gender m or f with lemma in -ь: ".. lemma)
end
end
if rfind(lemma, "[ыиЫИ][" .. AC .. GR .. "]?$") then
error("If this is a plural lemma, gender must be specified: " .. lemma)
elseif rfind(lemma, "[иИіІуУыЫѣѢэЭюЮѵѴ]" .. DIA .. "?[" .. AC .. GR .. "]?$") then
error("Don't know how to decline lemma ending in this type of vowel: " .. lemma)
end
return lemma, tr, ""
end
local plural_variant_detection_map = {
[""] = {["-ья"]="-ья"},
["ъ"] = {["-ья"]="ъ-ья"},
}
local special_case_1_to_plural_variant = {
[""] = "-а",
["ъ"] = "ъ-а",
["й"] = "й-я",
["ь-m"] = "ь-я",
["о"] = "о-и",
-- these last two are here to avoid getting errors in that checks for
-- compatibility with special case 1; the basic variants of these decls
-- don't actually exist
["(ишк)о"] = "(ишк)о-и",
["(ищ)е"] = "(ищ)е-и",
}
local function map_decl(decl, fun)
if rfind(decl, "/") then
local split_decl = rsplit(decl, "/")
if #split_decl ~= 2 then
error("Mixed declensional class " .. decl
.. "needs exactly two classes, singular and plural")
end
return fun(split_decl[1]) .. "/" .. fun(split_decl[2])
else
return fun(decl)
end
end
-- Canonicalize decl class into non-accented and alias-resolved form;
-- but note that some canonical decl class names with an accent in them
-- (e.g. е́, not the same as е, whose accented version is ё; and various
-- adjective declensions).
local function canonicalize_decl(decl, old)
local function do_canon(decl)
-- remove accents, but not from е́ (for adj decls, accent matters
-- as well but we handle that by mapping the accent to a stress pattern
-- and then to the accented version in determine_stress_variant())
if decl ~= "е́" then
decl = com.remove_accents(decl)
end
local decl_aliases = old and declensions_old_aliases or declensions_aliases
local decl_cats = old and declensions_old_cat or declensions_cat
if decl_aliases[decl] then
-- If we find an alias, map it.
decl = decl_aliases[decl]
elseif not decl_cats[decl] then
error("Unrecognized declension class " .. decl)
end
return decl
end
return map_decl(decl, do_canon)
end
-- Attempt to determine the actual declension (including plural variants)
-- based on a combination of the declension the user specified, what can be
-- detected from the lemma, and special case (1), if given in the declension.
-- DECL is the value the user passed for the declension field, after
-- extraneous annotations (special cases (1) and (2), * for reducible,
-- ё for ё/ё alternation and a ; that may precede ё) have been stripped off.
-- What's left is one of the following:
--
-- 1. Blank, meaning to autodetect the declension from the lemma
-- 2. A hyphen followed by a declension variant (-ья, -ин, -ишко, -ище; see
-- long comment at top of file)
-- 3. A gender (m, f, n, 3f)
-- 4. A gender plus declension variant (e.g. f-ья)
-- 5. An actual declension, possibly including a plural variant (e.g. о-и) or
-- a slash declension (e.g. я/-ья, used for the noun дядя).
--
-- Return seven args: stem (lemma minus ending), translit, canonicalized
-- declension, explicitly specified gender if any (m, f, n or nil), whether
-- the specified declension or detected ending was accented, whether the
-- detected ending was pl, and whether the declension was autodetected
-- (corresponds to cases where a full word with ending attached is required
-- in the lemma field). "Canonicalized" means after autodetection, with
-- accents removed, with any aliases mapped to their canonical versions
-- and with any requested declension variants applied. The result is either a
-- declension that will have a categorization entry (in declensions_cat[] or
-- declensions_old_cat[]) or a slash declension where each part similarly has
-- a categorization entry.
--
-- Note that gender is never required when an explicit declension is given,
-- and in connection with stem autodetection is required only when the lemma
-- either ends in -ь or is plural.
determine_decl = function(lemma, tr, decl, args)
-- Assume we're passed a value for DECL of types 1-4 above, and
-- fetch gender and requested declension variant.
local stem
local want_ya_plural, orig_pl_ending, variant
local was_autodetected
local gender = rmatch(decl, "^(3?[mfn]?)$")
if not gender then
gender, variant = rmatch(decl, "^(3?[mfn]?)(%-[^%-]+)$")
-- But be careful with explicit declensions like -а that look like
-- variants without gender (FIXME, eventually we should maybe do
-- something about the potential ambiguity).
if gender == "" and not m_table.contains({"-ья", "-ин", "-ишко", "-ище"}, variant) then
gender, variant = nil, nil
end
end
-- If DECL is of type 1-4, handle declension variants and detect
-- the actual declension from the lemma.
if gender then
-- Check for declension variants
if variant then
if variant == "-ья" then
want_ya_plural = "-ья"
else
-- Sanity-check remaining declension variants, which need
-- specific values of animacy, gender and special-case (1)
local sc1_needed
local animate_needed
if variant == "-ишко" then
animate_needed = false
sc1_needed = true
elseif variant == "-ище" then
animate_needed = true
sc1_needed = true
elseif variant == "-ин" then
animate_needed = true
sc1_needed = false
else
-- WARNING: If adding another variant, you need to also
-- add to the list farther above.
error("Unrecognized declension variant " .. variant .. ", should be -ья, -ин, -ишко or -ище")
end
if sc1_needed and not args.want_sc1 then
error("Declension variant " .. variant .. " must be used with special case (1)")
elseif sc1_needed == false and args.want_sc1 then
error("Declension variant " .. variant .. " must not be used with special case (1)")
end
if animate_needed and args.thisa ~= "a" then
error("Declension variant " .. variant .. " must be specified as animate")
elseif animate_needed == false and args.thisa == "a" then
error("Declension variant " .. variant .. " must not be specified as animate")
end
if gender ~= "" and gender ~= "m" then
error("Declension variant " .. variant .. " should be used with the masculine gender")
end
end
end
stem, tr, decl, orig_pl_ending = detect_lemma_type(lemma, tr, gender,
args, variant)
was_autodetected = true
else
stem, tr = lemma, tr
end
-- Now canonicalize gender
if gender == "3f" then
gender = "f"
elseif gender == "" then
gender = nil
end
-- The ending should be treated as accented if either the original singular
-- or plural ending was accented, or if the stem is non-syllabic.
local was_accented = com.is_stressed(decl) or
orig_pl_ending and com.is_stressed(orig_pl_ending) or
com.is_nonsyllabic(stem)
local was_plural = not not orig_pl_ending
decl = canonicalize_decl(decl, args.old)
-- The rest of this code concerns plural variants. It's somewhat
-- complicated because there are potentially four sources of plural
-- variants (not to mention plural variants constructed using slash
-- notation):
--
-- 1. A user-requested plural variant in declension types 2 or 4 above
-- (currently only -ья)
-- 2. An explicit plural variant encoded in an explicit declension of
-- type 5 above
-- 3. An autodetected plural variant (which will happen in some cases
-- when autodetection is performed on a nominative plural)
-- 4. A plural variant derived using special case (1).
--
-- Up to three actual plural variants might exist (e.g. if the user
-- specifies a DECL value or 'm-ья(1)' and a STEM ending in -а,
-- although not all three can ever be compatible because -ья and (1)
-- are never compatible). We can't have all four because if there's
-- an explicit plural variant, there won't be a user-requested or
-- autodetected plural variant.
--
-- The goal below is to do two things: Check that all available plural
-- variants are the same, and generate the actual declension.
-- If we have a type-2 or type-3 variant, we already have the actual
-- declension; else we need to use a table to map the basic declension
-- to the one with the plural variant encoded in it.
--
-- NOTE: The code below was written with a more general plural-variant
-- system. It probably can be simplified a lot now.
-- 1: Handle explicit decl with slash variant
if rfind(decl, "/") then
if want_ya_plural then
-- Don't think this can happen
error("Plural variant " .. want_ya_plural .. " not compatible with slash declension " .. decl)
end
if args.want_sc1 then
error("Special case (1) not compatible with slash declension" .. decl)
end
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- 2: Retrieve explicitly specified or autodetected decl and pl. variant
local basic_decl, detected_or_explicit_plural = rmatch(decl, "^(.*)(%-[^mf]+)$")
if basic_decl == "ь" then
basic_decl = "ь-m"
end
basic_decl = basic_decl or decl
-- 3: Any user-requested plural variant must agree with explicit or
-- autodetected variant.
if want_ya_plural and detected_or_explicit_plural and want_ya_plural ~= detected_or_explicit_plural then
error("Plural variant " .. want_ya_plural .. " requested but plural variant " .. detected_or_explicit_plural .. " detected from plural stem")
end
-- 4: Handle special case (1). Derive the full declension, make sure its
-- plural variant matches any other available plural variants, and
-- return the declension.
if args.want_sc1 then
local sc1_decl = special_case_1_to_plural_variant[basic_decl] or
error("Special case (1) not compatible with declension " .. basic_decl)
local sc1_plural = rsub(sc1_decl, "^.*%-", "-")
local other_plural = want_ya_plural or detected_or_explicit_plural
if other_plural and sc1_plural ~= other_plural then
error("Plural variant " .. other_plural .. " specified or detected, but special case (1) calls for plural variant " .. sc1_plural)
end
return stem, tr, sc1_decl, gender, was_accented, was_plural, was_autodetected
end
-- 5: Handle user-requested plural variant without explicit or detected
-- one. (If an explicit or detected one exists, we've already checked
-- that it agrees with the user-requested one, and so we already have
-- our full declension.)
if want_ya_plural and not detected_or_explicit_plural then
local variant_decl
if plural_variant_detection_map[decl] then
variant_decl = plural_variant_detection_map[decl][want_ya_plural]
end
if variant_decl then
return stem, tr, variant_decl, gender, was_accented, was_plural, was_autodetected
else
return stem, tr, decl .. (args.old and "/ъ-ья" or "/-ья"), gender, was_accented, was_plural, was_autodetected
end
end
-- 6: Just return the full declension, which will include any available
-- plural variant in it.
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- Convert soft adjectival declensions into hard ones following certain
-- stem-final consonants. FIXME: We call this in two places, once
-- to handle auto-detection and once to handle explicit declensions; but
-- in the former case we end up calling it twice.
local function determine_adj_stem_variant(decl, stem)
local iend = rmatch(decl, "^%+[іи]([йея]?)$")
-- Convert ій/ий to ый after velar or sibilant. This is important for
-- velars; doesn't really matter one way or the other for sibilants as
-- the sibilant rules will convert both sets of endings to the same
-- thing (whereas there will be a difference with о vs. е for velars).
if iend and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl = "+ы" .. iend
-- The following is necessary for -ц, unclear if makes sense for
-- sibilants. (Would be necessary -- I think -- if we were
-- inferring short adjective forms, but we're not.)
elseif decl == "+ее" and rfind(stem, "[" .. com.sib_c .. "]$") then
decl = "+ое"
end
return decl
end
-- Attempt to determine the actual adjective declension based on a
-- combination of the declension the user specified and what can be detected
-- from the stem. DECL is the value the user passed for the declension field,
-- after extraneous annotations have been removed (although none are probably
-- relevant here). What's left is one of the following, which always begins
-- with +:
--
-- 1. +, meaning to autodetect the declension from the stem
-- 2. +ь, same as + but selects +ьий instead of +ий if lemma ends in -ий
-- 3. +short, +mixed or +proper, with the declension partly specified but
-- the particular gender/number-specific short/mixed variant to be
-- autodetected
-- 4. A gender (+m, +f or +n), used only for detecting the singular of
-- plural-form lemmas (this is primarily used in conjunction with template
-- ru-noun+, to explicitly specify the gender; for the actual declension,
-- it doesn't much matter what singular gender we pick since we're a
-- plural only)
-- 5. A gender plus short/mixed/proper/ь (e.g. +f-mixed), again with the gender
-- used only for detecting the singular of plural-form short/mixed lemmas
-- 6. An actual declension, possibly including a slash declension
-- (WARNING: Unclear if slash declensions will work, especially those
-- that are adjective/noun combinations)
--
-- Returns the same seven args as for determine_decl(). The returned
-- declension will always begin with +.
detect_adj_type = function(lemma, tr, decl, old)
local was_autodetected
local base, ending
local basedecl, g = rmatch(decl, "^(%+)([mfn])$")
if not basedecl then
g, basedecl = rmatch(decl, "^%+([mfn])%-([a-zь]+)$")
if basedecl then
basedecl = "+" .. basedecl
end
end
decl = basedecl or decl
if decl == "+" or decl == "+ь" then
local loc = rfind(lemma, "[аеиіоыя][" .. AC .. GR .. "]?[йея]$") or rfind(lemma, "ь[йея]$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
end
if ending == "ий" and decl == "+ь" then
decl = "+ьий"
elseif ending == "ій" and decl == "+ь" then
decl = "+ьій"
elseif ending then
decl = "+" .. ending
else
local loc, shortmixed = rfind(lemma, "[аоы][" .. AC .. GR .. "]?$") or rfind(lemma, "ъ?$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
shortmixed = rfind(base, "^[" .. com.uppercase .. "].*[иы]" .. AC .. "н$") and "stressed-proper" or -- accented
rfind(base, "^[" .. com.uppercase .. "].*[иы]н$") and "proper" or --not accented
rlfind(base, "[ёео][" .. AC .. GR .. "]?в$") and "short" or
rlfind(base, "[ыи]" .. AC .. "н$") and "stressed-short" or -- accented
rlfind(base, "[ыи]н$") and "mixed" --not accented
end
if not shortmixed then
error("Cannot determine stem type of adjective: " .. lemma)
end
decl = "+" .. ending .. "-" .. shortmixed
end
was_autodetected = true
elseif m_table.contains({"+short", "+mixed", "+proper"}, decl) then
base, ending = rmatch(lemma, "^(.-)([оаыъ]?[" .. AC .. GR .. "]?)$")
assert(base)
local shortmixed = usub(decl, 2)
if rlfind(base, "[ыи]" .. AC .. "н$") then -- accented
if shortmixed == "short" then shortmixed = "stressed-short"
elseif shortmixed == "proper" then shortmixed = "stressed-proper"
end
end
decl = "+" .. ending .. "-" .. shortmixed
was_autodetected = true
else
base = lemma
end
if ending and ending ~= "" then
tr = com.strip_tr_ending(tr, ending)
end
-- Remove any accents from the declension, but not their presence.
-- We will convert was_accented into stress pattern b, and convert that
-- back to an accented version in determine_stress_variant(). This way
-- we end up with the stressed version whether the user placed an accent
-- in the ending or decl or specified stress pattern b.
-- FIXME, might not work in the presence of slash declensions
local was_accented = com.is_stressed(decl)
decl = com.remove_accents(decl)
decl = map_decl(decl, function(decl)
return determine_adj_stem_variant(decl, base)
end)
local singdecl
if decl == "+ые" then
singdecl = (g == "m" or not g) and (was_accented and "+ой" or "+ый") or not old and g == "f" and "+ая" or not old and g == "n" and "+ое"
elseif decl == "+ыя" and old then
singdecl = (g == "f" or not g) and "+ая" or g == "n" and "+ое"
elseif decl == "+ие" and not old then
singdecl = (g == "m" or not g) and "+ий" or g == "f" and "+яя" or g == "n" and "+ее"
elseif decl == "+іе" and old and (g == "m" or not g) then
singdecl = "+ій"
elseif decl == "+ія" and old then
singdecl = (g == "f" or not g) and "+яя" or g == "n" and "+ее"
elseif decl == "+ьи" then
singdecl = (g == "m" or not g) and (old and "+ьій" or "+ьий") or g == "f" and "+ья" or g == "n" and "+ье"
elseif rfind(decl, "^%+ы%-") then -- decl +ы-mixed or similar
local beg = (g == "m" or not g) and (old and "ъ" or "") or g == "f" and "а" or g == "n" and "о"
singdecl = beg and "+" .. beg .. usub(decl, 3)
end
if singdecl then
was_plural = true
decl = singdecl
end
return base, tr, canonicalize_decl(decl, old), g, was_accented, was_plural, was_autodetected
end
-- If stress pattern omitted, detect it based on whether ending is stressed
-- or the decl class or stem accent calls for inherent stress, defaulting to
-- pattern a. This is run after alias resolution and accent removal of DECL;
-- WAS_ACCENTED indicates whether the ending was originally stressed.
-- FIXME: This is run before splitting slash patterns but should be run after.
detect_stress_pattern = function(stem, decl, decl_cats, reducible,
was_plural, was_accented)
-- ёнок and ёночек always bear stress
if rfind(decl, "ёнокъ?") or rfind(decl, "ёночекъ?") then
return "b"
-- stressed suffix и́н; missing in plural and true endings don't bear stress
-- (except for exceptional господи́н)
elseif rfind(decl, "инъ?") and was_accented then
return "d"
-- Adjectival -ой always bears the stress
elseif rfind(decl, "%+ой") then
return "b"
-- Adjectival stressed-short, stressed-proper bears the stress
elseif rfind(decl, "^%+.*%-stressed") then
return "b"
-- Pattern b if ending was accented by user
elseif was_accented then
return "b"
-- Nonsyllabic stem means pattern b
elseif com.is_nonsyllabic(stem) then
return "b"
-- Accent on reducible vowel in masc nom sg (not plural) means pattern b.
-- Think about whether we want to enable this.
-- elseif reducible and not was_plural then
-- -- FIXME hack. Eliminate plural part of slash declension.
-- decl = rsub(decl, "/.*", "")
-- if decl_cats[decl] and decl_cats[decl].g == "m" then
-- if com.is_ending_stressed(stem) or com.is_monosyllabic(stem) then
-- return "b"
-- end
-- end
end
return "a"
end
-- In certain special cases, depending on the declension, we override the
-- user-specified stress pattern and convert it to something else.
-- NOTE: This function is run after alias resolution and accent removal.
-- FIXME: It's also run before splitting slash patterns but should be run after.
override_stress_pattern = function(decl, stress)
-- ёнок and ёночек always bear stress; if user specified a,
-- convert to b. Don't do this with slash patterns (see FIXME above).
if stress == "a" and (rfind(decl, "^ёнокъ?$") or rfind(decl, "^ёночекъ?$")) then
return "b"
end
return stress
end
-- Canonicalize an adjectival declension to either the stressed or unstressed
-- variant depending on the stress. Ultimately this is what ensures that
-- the user's stress mark on an adjectival ending is respected.
determine_stress_variant = function(decl, stress)
if stress == "b" then
if decl == "+ая" then
return "+а́я"
elseif decl == "+ое" then
return "+о́е"
else
-- Convert +...-short to +...-stressed-short and same for -proper
local b, e = rmatch(decl, "^%+(.*)%-(short)$")
if not b then
b, e = rmatch(decl, "^%+(.*)%-(proper)$")
end
if b and not rfind(b, "%-stressed") then
return "+" .. b .. "-stressed-" .. e
end
end
end
return decl
end
-- Canonicalize a declension based on the final stem consonant, in
-- particular converting soft declensions to hard ones after velars and/or
-- sibilants. FIXME: We also do this canonicalization earlier on during
-- auto-detection (determine_adj_stem_variant() is called by
-- detect_adj_type(), and code in detect_lemma_type() does the equivalent
-- of the first clause below). Doing it here ensures that explicitly
-- specified declensions get handled as well, but it would be nice to not
-- do the same thing twice in the auto-detection case.
determine_stem_variant = function(decl, stem)
if decl == "е" and rfind(stem, "[" .. com.sib_c .. "]$") then
return "о"
end
return determine_adj_stem_variant(decl, stem)
end
is_reducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "3rd" and decl_cat.g == "f" or decl_cat.g == "m" then
return true
else
return false
end
end
-- Reduce nom sg to stem by eliminating the "epenthetic" vowel. Applies to
-- masculine 2nd-declension hard and soft, and 3rd-declension feminine in
-- -ь. STEM and DECL are after determine_decl(), before converting
-- outward-facing declensions to inward ones.
function export.reduce_nom_sg_stem(stem, tr, decl, soft_n, can_err)
local full_stem = stem .. (decl == "й" and decl or "")
local full_tr = tr and tr .. (decl == "й" and "j" or "")
local ret, rettr = com.reduce_stem(full_stem, full_tr, soft_n)
if not ret and can_err then
error("Unable to reduce stem " .. stem)
end
return ret, rettr
end
is_dereducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "1st" or decl_cat.decl == "2nd" and decl_cat.g == "n" then
return true
else
return false
end
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. dereducible nouns
-- in -ня.
add_bare_suffix = function(bare, baretr, old, sgdc, dereduced)
if old and sgdc.hard == "hard" then
-- Final -ъ isn't transliterated
return bare .. "ъ", baretr
elseif sgdc.hard == "soft" or sgdc.hard == "palatal" then
-- This next clause corresponds to a special case in Vitalik's module.
-- It says that nouns in -ня (accent class a) have gen pl without
-- trailing -ь. It appears to apply to most nouns in -ня (possibly
-- all in -льня), but ку́хня (gen pl ку́хонь) and дерéвня (gen pl
-- дереве́нь) is an exception. (Vitalik's module has an extra
-- condition here 'stress == "a"' that would exclude дере́вня but I
-- don't think this condition is in Zaliznyak, as he indicates
-- дере́вня as having an exceptional genitive plural.)
if dereduced and rfind(bare, "[нН]$") and sgdc.decl == "1st" then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
-- Final -ъ isn't transliterated
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return bare .. "й", baretr and (baretr .. "j")
else
return bare .. "ь", baretr and (baretr .. "ʹ")
end
else
return bare, baretr
end
end
-- Dereduce stem to the form found in the gen pl (and maybe nom sg) by
-- inserting an epenthetic vowel. Applies to 1st declension and 2nd
-- declension neuter, and to 2nd declension masculine when the stem was
-- specified as a plural form (in which case we're deriving the nom sg,
-- and also the gen pl in the alt-gen-pl scenario). STEM and DECL are
-- after determine_decl(), before converting outward-facing declensions
-- to inward ones. STRESS is the stess pattern.
function export.dereduce_nom_sg_stem(stem, tr, sgdc, stress, old, can_err)
local epenthetic_stress = ending_stressed_gen_pl_patterns[stress]
local ret, rettr = com.dereduce_stem(stem, tr, epenthetic_stress)
if not ret then
if can_err then
error("Unable to dereduce stem " .. stem)
else
return nil, nil
end
end
return add_bare_suffix(ret, rettr, old, sgdc, true)
end
--------------------------------------------------------------------------
-- Second-declension masculine --
--------------------------------------------------------------------------
----------------- Masculine hard -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style).
declensions_old["ъ"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and "е́й" or "о́въ"
end,
["alt_gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["ъ"] = { decl="2nd", hard="hard", g="m" }
-- Normal mapping of old ъ would be "" (blank), but we set up "#" as an alias
-- so we have a way of referring to it without defaulting if need be and
-- distinct from auto-detection (e.g. in the second stem of a word, or to
-- override autodetection of -ёнок or -ин -- the latter is necessary in the
-- case of семьянин).
declensions_aliases["#"] = ""
----------------- Masculine hard, irregular plural -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg nom pl -а.
declensions_old["ъ-а"] = mw.clone(declensions_old["ъ"])
declensions_old["ъ-а"]["nom_pl"] = "а́"
declensions_old_cat["ъ-а"] = { decl="2nd", hard="hard", g="m", alt_nom_pl=true }
declensions_aliases["#-a"] = "-a"
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg soft pl -ья.
-- Differs from the normal declension throughout the plural.
declensions_old["ъ-ья"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = "ьёвъ",
["alt_gen_pl"] = "е́й",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ъ-ья"] = { decl="2nd", hard="hard", g="m", irregpl=true }
declensions_aliases["#-ья"] = "-ья"
----------------- Masculine hard, suffixed, irregular plural -------------------
declensions_old["инъ"] = {
["nom_sg"] = "и́нъ",
["gen_sg"] = "и́на",
["dat_sg"] = "и́ну",
["acc_sg"] = nil,
["ins_sg"] = "и́номъ",
["pre_sg"] = "и́нѣ",
["nom_pl"] = "е́",
["gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["инъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old["ёнокъ"] = {
["nom_sg"] = "ёнокъ",
["gen_sg"] = "ёнка",
["dat_sg"] = "ёнку",
["acc_sg"] = nil,
["ins_sg"] = "ёнкомъ",
["pre_sg"] = "ёнкѣ",
["nom_pl"] = "я́та",
["gen_pl"] = "я́тъ",
["dat_pl"] = "я́тамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тами",
["pre_pl"] = "я́тахъ",
}
declensions_old_cat["ёнокъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["онокъ"] = "ёнокъ"
declensions_old_aliases["енокъ"] = "ёнокъ"
declensions_old["ёночекъ"] = {
["nom_sg"] = "ёночекъ",
["gen_sg"] = "ёночка",
["dat_sg"] = "ёночку",
["acc_sg"] = nil,
["ins_sg"] = "ёночкомъ",
["pre_sg"] = "ёночкѣ",
["nom_pl"] = "я́тки",
["gen_pl"] = "я́токъ",
["dat_pl"] = "я́ткамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тками",
["pre_pl"] = "я́ткахъ",
}
declensions_old_cat["ёночекъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["оночекъ"] = "ёночекъ"
declensions_old_aliases["еночекъ"] = "ёночекъ"
----------------- Masculine soft -------------------
-- Normal soft-masculine declension in -ь
declensions_old["ь-m"] = {
["nom_sg"] = "ь",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["alt_gen_pl"] = "ь",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-m"] = { decl="2nd", hard="soft", g="m" }
-- Soft-masculine declension in -ь with irreg nom pl -я
declensions_old["ь-я"] = mw.clone(declensions_old["ь-m"])
declensions_old["ь-я"]["nom_pl"] = "я́"
declensions_old_cat["ь-я"] = { decl="2nd", hard="soft", g="m", alt_nom_pl=true }
----------------- Masculine palatal -------------------
-- Masculine declension in palatal -й
declensions_old["й"] = {
["nom_sg"] = "й",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = "ёвъ",
["alt_gen_pl"] = "й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["й"] = { decl="2nd", hard="palatal", g="m" }
declensions_old["й-я"] = mw.clone(declensions_old["й"])
declensions_old["й-я"]["nom_pl"] = "я́"
declensions_old_cat["й-я"] = { decl="2nd", hard="palatal", g="m", alt_nom_pl=true }
--------------------------------------------------------------------------
-- First-declension feminine --
--------------------------------------------------------------------------
----------------- Feminine hard -------------------
-- Hard-feminine declension in -а
declensions_old["а"] = {
["nom_sg"] = "а́",
["gen_sg"] = "ы́",
["dat_sg"] = "ѣ́",
["acc_sg"] = "у́",
["ins_sg"] = {"о́й<insa>", "о́ю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["а"] = { decl="1st", hard="hard", g="f" }
----------------- Feminine soft -------------------
-- Soft-feminine declension in -я
declensions_old["я"] = {
["nom_sg"] = "я́",
["gen_sg"] = "и́",
["dat_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_dat_sg_patterns[stress] and "и" or "ѣ́"
end,
["acc_sg"] = "ю́",
["ins_sg"] = {"ёй<insa>", "ёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "]́?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["я"] = { decl="1st", hard="soft", g="f" }
-- Soft-feminine declension in -ья.
-- Almost like ь + -я endings except for genitive plural.
declensions_old["ья"] = {
["nom_sg"] = "ья́",
["gen_sg"] = "ьи́",
["dat_sg"] = "ьѣ́",
["acc_sg"] = "ью́",
["ins_sg"] = {"ьёй<insa>", "ьёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ьи́",
["gen_pl"] = function(stem, stress)
-- circumflex accent is a signal that forces stress, particularly
-- in accent pattern d/d'.
return (ending_stressed_gen_pl_patterns[stress] or stress == "d" or stress == "d'") and "е̂й" or "ий"
end,
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ья"] = {
decl="1st", hard="soft", g="f",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
--------------------------------------------------------------------------
-- Second-declension neuter --
--------------------------------------------------------------------------
----------------- Neuter hard -------------------
-- Normal hard-neuter declension in -о
declensions_old["о"] = {
["nom_sg"] = "о́",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "о́" or nil
end,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "а́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "о́въ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["о"] = { decl="2nd", hard="hard", g="n" }
-- Hard-neuter declension in -о with irreg nom pl -и
declensions_old["о-и"] = mw.clone(declensions_old["о"])
declensions_old["о-и"]["nom_pl"] = "ы́"
declensions_old_cat["о-и"] = { decl="2nd", hard="hard", g="n", alt_nom_pl=true }
declensions_old_aliases["о-ы"] = "о-и"
-- Masculine-gender neuter-form declension in -(ишк)о with irreg nom pl -и,
-- with colloquial feminine endings in some of the singular cases
-- (§5 p. 74 of Zaliznyak)
declensions_old["(ишк)о-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ишк)о-и"]["gen_sg"] = {"а́", "ы́1"}
declensions_old["(ишк)о-и"]["dat_sg"] = {"у́", "ѣ́1"}
declensions_old["(ишк)о-и"]["ins_sg"] = {"о́мъ", "о́й1"}
declensions_old_cat["(ишк)о-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ишк)о-и"] = "<sup>1</sup> Colloquial."
-- Masculine-gender animate neuter-form declension in -(ищ)е with irreg
-- nom pl -и, with colloquial feminine endings in some of the singular cases
-- (§4 p. 74 of Zaliznyak)
declensions_old["(ищ)е-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ищ)е-и"]["acc_sg"] = {"а́", "у́1"}
declensions_old["(ищ)е-и"]["gen_sg"] = {"а́", "ы́2"}
declensions_old["(ищ)е-и"]["dat_sg"] = {"у́", "ѣ́2"}
declensions_old["(ищ)е-и"]["ins_sg"] = {"о́мъ", "о́й2"}
declensions_old_cat["(ищ)е-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ищ)е-и"] = "<sup>1</sup> Colloquial.<br /><sup>2</sup> Less common, more colloquial."
----------------- Neuter soft -------------------
-- Soft-neuter declension in -е (stressed -ё)
declensions_old["е"] = {
["nom_sg"] = "ё",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ё" or nil
end,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е"] = {
singular = function(suffix)
if suffix == "ё" then
return "ending in -ё"
else
return {}
end
end,
decl="2nd", hard="soft", g="n", gensg=true
}
-- User-facing declension type "ё" = "е"
declensions_old_aliases["ё"] = "е"
-- Rare soft-neuter declension in stressed -е́ (e.g. муде́, бытие́)
declensions_old["е́"] = {
["nom_sg"] = "е́",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "е́" or nil
end,
["ins_sg"] = "е́мъ",
["pre_sg"] = function(stem, stress)
-- FIXME!!! Are we sure about this condition? This is what was
-- found in the old template, but the related -е declension has
-- -ие prep sg ending -(и)и only when *not* stressed.
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and "и́" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "й" or "е́й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е́"] = {
singular = "ending in stressed -е",
decl="2nd", hard="soft", g="n", gensg=true
}
-- Soft-neuter declension in unstressed -ье (stressed -ьё).
declensions_old["ье"] = {
["nom_sg"] = "ьё",
["gen_sg"] = "ья́",
["dat_sg"] = "ью́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ьё" or nil
end,
["ins_sg"] = "ьёмъ",
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and "е́й" or "ий"
end,
["alt_gen_pl"] = "ьёвъ",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ье"] = {
decl="2nd", hard="soft", g="n",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
declensions_old_aliases["ьё"] = "ье"
--------------------------------------------------------------------------
-- Third declension --
--------------------------------------------------------------------------
declensions_old["ь-f"] = {
["nom_sg"] = "ь",
["gen_sg"] = "и́",
["dat_sg"] = "и́",
["acc_sg"] = "ь",
["ins_sg"] = "ью́",
["pre_sg"] = "и́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-f"] = { decl="3rd", hard="soft", g="f" }
declensions_old["мя"] = {
["nom_sg"] = "мя",
["gen_sg"] = "мени",
["dat_sg"] = "мени",
["acc_sg"] = nil,
["ins_sg"] = "менемъ",
["pre_sg"] = "мени",
["nom_pl"] = "мена́",
["gen_pl"] = "мёнъ",
["dat_pl"] = "мена́мъ",
["acc_pl"] = nil,
["ins_pl"] = "мена́ми",
["pre_pl"] = "мена́хъ",
}
declensions_old_cat["мя"] = { decl="3rd", hard="soft", g="n", cant_reduce=true }
--------------------------------------------------------------------------
-- Indeclinable --
--------------------------------------------------------------------------
-- Indeclinable declension; no endings.
declensions_old["$"] = {
["nom_sg"] = "",
["gen_sg"] = "",
["dat_sg"] = "",
["acc_sg"] = nil,
["ins_sg"] = "",
["pre_sg"] = "",
["nom_pl"] = "",
["gen_pl"] = "",
["dat_pl"] = "",
["acc_pl"] = nil,
["ins_pl"] = "",
["pre_pl"] = "",
}
declensions_old_cat["$"] = { decl="indeclinable", hard="none", g="none" }
--------------------------------------------------------------------------
-- Adjectival --
--------------------------------------------------------------------------
-- This needs to be up here because it is called just below.
local function old_to_new(v)
v = rsub(v, "ъ$", "")
v = rsub(v, "^ъ", "")
v = rsub(v, "(%A)ъ", "%1")
v = rsub(v, "ъ(%A)", "%1")
v = rsub(v, "і", "и")
v = rsub(v, "ѣ", "е")
return v
end
-- Meaning of entry is:
-- 1. The declension name in module ru-adjective
-- 2. The masculine declension name in this module
-- 3. The neuter declension name in this module
-- 4. The feminine declension name in this module
-- 5. The value of hard= for the declensions_cat entry
-- 6. The value of decl= for the declensions_cat entry
-- 7. The value of possadj= for the declensions_cat entry (true if possessive
-- or similar type of adjective)
local adj_decl_map = {
{"ый", "ый", "ое", "ая", "hard", "long", false},
{"ій", "ій", "ее", "яя", "soft", "long", false},
{"ой", "ой", "о́е", "а́я", "hard", "long", false},
{"ьій", "ьій", "ье", "ья", "palatal", "long", true},
{"short", "ъ-short", "о-short", "а-short", "hard", "short", true},
{"mixed", "ъ-mixed", "о-mixed", "а-mixed", "hard", "mixed", true},
{"proper", "ъ-proper", "о-proper", "а-proper", "hard", "proper", true},
{"stressed-short", "ъ-stressed-short", "о-stressed-short", "а-stressed-short", "hard", "short", true},
{"stressed-proper", "ъ-stressed-proper", "о-stressed-proper", "а-stressed-proper", "hard", "proper", true},
}
local function get_adjectival_decl(adjtype, gender, old)
local decl, intnotes = m_ru_adj.get_nominal_decl(adjtype, gender, old)
-- hack fem ins_sg to insert <insa>, <insb>; see concat_word_forms_1()
if gender == "f" and type(decl["ins_sg"]) == "table" and #decl["ins_sg"] == 2 then
decl["ins_sg"][1] = decl["ins_sg"][1] .. "<insa>"
decl["ins_sg"][2] = decl["ins_sg"][2] .. "<insb>"
end
return decl, intnotes
end
for _, declspec in ipairs(adj_decl_map) do
local oadjdecl = declspec[1]
local nadjdecl = old_to_new(oadjdecl)
local odecl_by_gender =
{m="+" .. declspec[2], n="+" .. declspec[3], f="+" .. declspec[4]}
local hard = declspec[5]
local decltype = declspec[6]
local possadj = declspec[7]
for _, g in ipairs({"m", "n", "f"}) do
local odecl = odecl_by_gender[g]
local ndecl = old_to_new(odecl)
declensions_old[odecl], internal_notes_table_old[odecl] =
get_adjectival_decl(oadjdecl, g, true)
declensions[ndecl], internal_notes_table[ndecl] =
get_adjectival_decl(nadjdecl, g, false)
declensions_old_cat[odecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
declensions_cat[ndecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
end
end
-- Set up some aliases.
declensions_old_aliases["+о́-short"] = "+о-stressed-short"
declensions_old_aliases["+а́-short"] = "+а-stressed-short"
declensions_old_aliases["+о́-proper"] = "+о-stressed-proper"
declensions_old_aliases["+а́-proper"] = "+а-stressed-proper"
declensions_aliases["+#-short"] = "+-short"
declensions_aliases["+#-mixed"] = "+-mixed"
declensions_aliases["+#-proper"] = "+-proper"
declensions_aliases["+#-stressed-short"] = "+-stressed-short"
declensions_aliases["+#-stressed-proper"] = "+-stressed-proper"
--------------------------------------------------------------------------
-- Populate new from old --
--------------------------------------------------------------------------
-- Function to convert an entry in an old declensions table to new.
local function old_decl_entry_to_new(v)
if not v then
return nil
elseif type(v) == "table" then
local new_entry = {}
for _, i in ipairs(v) do
table.insert(new_entry, old_decl_entry_to_new(i))
end
return new_entry
elseif type(v) == "function" then
return function(stem, suffix, args)
return old_decl_entry_to_new(v(stem, suffix, args))
end
else
return old_to_new(v)
end
end
-- Function to convert an old declensions table to new.
local function old_decl_to_new(odecl)
local ndecl = {}
for k, v in pairs(odecl) do
ndecl[k] = old_decl_entry_to_new(v)
end
return ndecl
end
-- Function to convert an entry in an old declensions_cat table to new.
local function old_decl_cat_entry_to_new(odecl_cat_entry)
if not odecl_cat_entry then
return nil
elseif type(odecl_cat_entry) == "function" then
return function(suffix)
return old_decl_cat_entry_to_new(odecl_cat_entry(suffix))
end
elseif type(odecl_cat_entry) == "table" then
local ndecl_cat_entry = {}
for k, v in pairs(odecl_cat_entry) do
ndecl_cat_entry[k] = old_decl_cat_entry_to_new(v)
end
return ndecl_cat_entry
elseif type(odecl_cat_entry) == "boolean" then
return odecl_cat_entry
else
assert(type(odecl_cat_entry) == "string")
return old_to_new(odecl_cat_entry)
end
end
-- Function to convert an old declensions_cat table to new.
local function old_decl_cat_to_new(odeclcat)
local ndeclcat = {}
for k, v in pairs(odeclcat) do
ndeclcat[k] = old_decl_cat_entry_to_new(v)
end
return ndeclcat
end
-- populate declensions[] from declensions_old[]
for odecltype, odecl in pairs(declensions_old) do
local ndecltype = old_to_new(odecltype)
if not declensions[ndecltype] then
declensions[ndecltype] = old_decl_to_new(odecl)
end
end
-- populate declensions_cat[] from declensions_old_cat[]
for odecltype, odeclcat in pairs(declensions_old_cat) do
local ndecltype = old_to_new(odecltype)
if not declensions_cat[ndecltype] then
declensions_cat[ndecltype] = old_decl_cat_to_new(odeclcat)
end
end
-- populate declensions_aliases[] from declensions_old_aliases[]
for ofrom, oto in pairs(declensions_old_aliases) do
local from = old_to_new(ofrom)
if not declensions_aliases[from] then
declensions_aliases[from] = old_to_new(oto)
end
end
-- populate internal_notes_table[] from internal_notes_table_old[]
for odecl, note in pairs(internal_notes_table_old) do
local ndecl = old_to_new(odecl)
if not internal_notes_table[ndecl] then
-- FIXME, should we be calling old_to_new() here?
internal_notes_table[ndecl] = note
end
end
--------------------------------------------------------------------------
-- Inflection functions --
--------------------------------------------------------------------------
-- Attach the stressed stem (or plural stem, or barestem) out of ARGS
-- to the unstressed suffix SUF, modifying the suffix as necessary for the
-- last letter of the stem (e.g. if it is velar, sibilant or ц). CASE is
-- the case form being created and is used to select the plural stem if
-- needed. Returns two values, the combined form and the modified suffix.
local function attach_unstressed(args, case, suf, was_stressed)
if suf == nil then
return nil, nil
elseif rfind(suf, CFLEX) then -- if suf has circumflex accent, it forces stressed
return attach_stressed(args, case, suf)
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.pl, args.pltr
end
if not stem and case == "ins_sg" then
stem, tr = args.ins_sg_stem, args.ins_sg_tr
end
if not stem then
stem, tr = args.stem, args.stemtr
end
if nom.nonsyllabic_suffixes[suf] then
-- If gen_pl, use special args.gen_pl_bare if given, else regular
-- args.bare if there isn't a plural stem. If nom_sg, always use
-- regular args.bare.
local barearg, bareargtr
if case == "gen_pl" then
barearg, bareargtr = args.gen_pl_bare, args.gen_pl_baretr
if not barearg and args.pl == args.stem then
barearg, bareargtr = args.bare, args.baretr
end
else
barearg, bareargtr = args.bare, args.baretr
end
local barestem = barearg or stem
local barestem, baretr
if barearg then
barestem, baretr = barearg, bareargtr
else
barestem, baretr = stem, tr
end
if was_stressed and case == "gen_pl" then
if not barearg then
local gen_pl_stem, gen_pl_tr = com.make_ending_stressed(stem, tr)
barestem, baretr = gen_pl_stem, gen_pl_tr
end
end
if rlfind(barestem, "[йьъ]$") then
suf = ""
else
if suf == "ъ" then
-- OK
elseif suf == "й" or suf == "ь" then
if barearg and case == "gen_pl" then
-- explicit bare or reducible, don't add -ь
suf = ""
elseif rfind(barestem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
-- not reducible, do add -ь and correct to -й if necessary
suf = "й"
else
suf = "ь"
end
end
end
return com.concat_russian_tr(barestem, baretr, suf, nil, "dopair"), suf
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Analogous to attach_unstressed() but for the unstressed stem and a
-- stressed suffix.
attach_stressed = function(args, case, suf)
if suf == nil then
return nil, nil
end
-- circumflex forces stress even when the accent pattern calls for no stress
suf = rsub(suf, "̂", AC)
if com.is_unstressed(suf) then
return attach_unstressed(args, case, suf, "was stressed")
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.upl, args.upltr
end
if not stem then
stem, tr = args.ustem, args.ustemtr
end
local rules = nom.stressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Attach the appropriate stressed or unstressed stem (or plural stem as
-- determined by CASE, or barestem) out of ARGS to the suffix SUF, which may
-- be a list of alternative suffixes (e.g. in the inst sg of feminine nouns).
-- Calls FUN (either attach_stressed() or attach_unstressed()) to do the work
-- for an individual suffix. Returns two values, a list of combined forms
-- and a list of the real suffixes used (which may be modified from the
-- passed-in suffixes, e.g. by removing stress marks or modifying vowels in
-- various ways after a stem-final velar, sibilant or ц). Each combined form
-- is a two-element list {stem, tr} (or a one-element list if tr is nil).
-- IRREG is true if this is an irregular form. We are handling the Nth word;
-- ISLAST is true if this is the last one.
local function attach_with(args, case, suf, fun, irreg, n, islast)
if type(suf) == "table" then
local all_combineds = {}
local all_realsufs = {}
for _, x in ipairs(suf) do
local combineds, realsufs =
attach_with(args, case, x, fun, irreg, n, islast)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
for _, realsuf in ipairs(realsufs) do
table.insert(all_realsufs, realsuf)
end
end
return all_combineds, all_realsufs
else
local combined, realsuf = fun(args, case, suf)
local irregsuf = irreg and {IRREGMARKER} or {""}
return {combined and com.concat_paired_russian_tr(
com.concat_paired_russian_tr(args["prefix" .. n], combined),
com.concat_paired_russian_tr(args["suffix" .. n], irregsuf)) or nil},
{realsuf and realsuf .. args["suffix" .. n][1] or nil}
end
end
-- Generate the form(s) and suffix(es) for CASE according to the declension
-- table DECL, using the attachment function FUN (one of attach_stressed()
-- or attach_unstressed()). IS_SLASH is true if this is a slash declension
-- (different declensions for singular and plural). We are handling the Nth
-- word; ISLAST is true if this is the last one.
local function gen_form(args, decl, case, stress, fun, is_slash, n, islast)
local irreg = false
if not args.suffixes[case] then
args.suffixes[case] = {}
end
local decl_sufs = args.old and declensions_old or declensions
decl_sufs = decl_sufs[decl]
local suf = decl_sufs[case]
local decl_cats = args.old and declensions_old_cat or declensions_cat
local ispl = rfind(case, "_pl")
if ispl and (decl_cats[decl].irregpl or args.pl and args.pl ~= args.stem or is_slash) then
irreg = true
end
if case == "nom_pl" and decl_cats[decl].alt_nom_pl then
irreg = true
end
if type(suf) == "function" then
suf = suf(ispl and args.pl or args.stem, stress, args)
end
if case == "gen_pl" and args.alt_gen_pl then
suf = decl_sufs.alt_gen_pl
irreg = true
if not suf then
error("No alternative genitive plural available for this declension class")
end
end
local combineds, realsufs = attach_with(args, case, suf, fun, irreg, n, islast)
for _, realsuf in ipairs(realsufs) do
args.any_non_nil[case] = true
args.this_any_non_nil[case] = true
insert_if_not(args.suffixes[case], realsuf)
end
return combineds
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
}
do_stress_pattern = function(stress, args, decl, number, n, islast)
local f = {}
for _, case in ipairs(decl_cases) do
if not number or (number == "sg" and rfind(case, "_sg")) or
(number == "pl" and rfind(case, "_pl")) then
f[case] = gen_form(args, decl, case, stress,
attachers[stress_patterns[stress][case]], not not number,
n, islast)
-- Turn empty form lists into nil to facilitate computation of
-- animate/inanimate accusatives below
if f[case] and #f[case] == 0 then
f[case] = nil
end
-- Compute linked versions of potential lemma cases, for use
-- in the ru-noun+ headword. We substitute the original lemma
-- (before removing links) for forms that are the same as the
-- lemma, if the original lemma has links.
if f[case] and (case == "nom_sg" or case == "nom_pl") then
local linked_forms = {}
for _, form in ipairs(f[case]) do
-- Return true if FORM is "close enough" to LEMMA that we can substitute the
-- linked form of the lemma. Currently this means exactly the same except that
-- we ignore acute and grave accent differences in monosyllables, and ignore
-- notes that may have been appended (e.g. the triangle marking irregularity).
local entry, notes = m_table_tools.separate_notes(form[1])
local lemma = args.lemma_no_links
local close_enough_to_lemma =
entry == lemma or (com.is_monosyllabic(entry) and
com.is_monosyllabic(lemma) and
com.remove_accents(entry) == com.remove_accents(lemma))
if close_enough_to_lemma and
rfind(args.orig_lemma, "%[%[") then
table.insert(linked_forms, {args.orig_lemma .. notes, args.lemmatr and args.lemmatr .. notes})
else
table.insert(linked_forms, form)
end
end
f[case .. "_linked"] = linked_forms
end
end
end
-- Set acc an/in variants now as appropriate. We used to do this in
-- handle_forms_and_overrides(), which simplified the handling of
-- nom/gen/acc overrides but caused problems for words like мазло and
-- трепло that had a mixture of nil and non-nil accusative forms.
local an = args.thisa
if not number or number == "sg" then
f.acc_sg_an = f.acc_sg_an or f.acc_sg or an == "i" and f.nom_sg or f.gen_sg
f.acc_sg_in = f.acc_sg_in or f.acc_sg or an == "a" and f.gen_sg or f.nom_sg
end
if not number or number == "pl" then
f.acc_pl_an = f.acc_pl_an or f.acc_pl or an == "i" and f.nom_pl or f.gen_pl
f.acc_pl_in = f.acc_pl_in or f.acc_pl or an == "a" and f.gen_pl or f.nom_pl
end
for case, forms in pairs(f) do
if not args.forms[case] then
args.forms[case] = {}
end
for _, form in ipairs(forms) do
insert_if_not(args.forms[case], form)
end
end
end
stress_patterns["a"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["b"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["b'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["c"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["d"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["d'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["e"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f''"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
ending_stressed_gen_pl_patterns = m_table.listToSet({"b", "b'", "c", "e", "f", "f'", "f''"})
ending_stressed_pre_sg_patterns = m_table.listToSet({"b", "b'", "d", "d'", "f", "f'", "f''"})
ending_stressed_dat_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_pl_patterns = m_table.listToSet({"b", "b'", "c"})
local numbers = {
["s"] = "ကိုန်ဨကဝုစ်",
["p"] = "ကိုန်ဗဟုဝစ်",
}
local old_title_temp = [=[မလဟုတ်စှ်ေကၠာပြုပြေၚ်ပြံၚ်လှာဲဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local extra_case_template, extra_case_template_with_plural
local internal_notes_template
local notes_template
local templates = {}
-- Convert a raw override into a canonicalized list of individual overrides.
-- If input is nil, so is output. Certain junk (e.g. <br/>) is removed,
-- and ~ and ~~ are substituted appropriately; ARGS and CASE are required for
-- this purpose. FORMS is the list of existing case forms and is currently
-- used only to retrieve the dat_sg for handling + in loc/par (this means
-- that any overrides of the dat_sg have to be handled before handling
-- overrides of loc/par). N is the suffix used to retrieve the override --
-- either a number for word-specific overrides, or an empty string for
-- overall overrides.
--
-- It will still be necessary to call m_table_tools.separate_notes() to separate
-- off any trailing "notes" (asterisks, superscript numbers, etc.), and
-- m_links.remove_links() to remove any links to get the raw override form.
canonicalize_override = function(args, case, forms, n)
local val = args[case .. n]
if not val then
return nil
end
-- clean <br /> that's in many multi-form entries and messes up linking
val = rsub(val, "<br%s*/>", "")
-- substitute ~ and ~~ and split by commas
local stem, manualtr
if rfind(case, "_pl") then
stem, manualtr = args.pl, args.pltr
end
if not stem then
stem, manualtr = args.stem, args.stemtr
end
local ustem, umanualtr = com.make_unstressed_once(stem, manualtr)
local stemtr, ustemtr = manualtr, umanualtr
local vals = rsplit(val, "%s*,%s*")
local retvals = {}
for _, val in ipairs(vals) do
local valru, valtr = com.split_russian_tr(val)
valru = rsub(valru, "~~", ustem)
valru = rsub(valru, "~", com.is_stressed(val) and ustem or stem)
if rfind(valru, "^%*") then
valru = rsub(valru, "^%*", "") .. HYPMARKER
end
if valtr then
stemtr = stemtr or com.translit_no_links(stem)
ustemtr = ustemtr or com.translit_no_links(ustem)
valtr = rsub(valtr, "~~", ustemtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and ustemtr or stemtr)
elseif val:find("~") and manualtr then
valtr = com.translit_no_links(val)
valtr = rsub(valtr, "~~", umanualtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and umanualtr or manualtr)
end
if valtr then
if valtr:sub(1, 1) == "*" then
valtr = valtr:sub(2) .. HYPMARKER
end
valtr = com.j_correction(valtr)
end
table.insert(retvals, {valru, valtr})
end
vals = retvals
-- handle + in loc/par meaning "the expected form"; NOTE: This requires
-- that dat_sg has already been processed!
if case == "loc" or case == "par" then
local new_vals = {}
for _, rutr in ipairs(vals) do
-- don't just handle + by itself in case the arg has в or на
-- or whatever attached to it
if rfind(rutr[1], "^%+") or rfind(rutr[1], "[%s%[|]%+") then
for _, dat in ipairs(forms["dat_sg"]) do
local ru, tr = rutr[1], rutr[2]
local datru, dattr = dat[1], dat[2]
local valru, valtr
-- separate off any footnote symbols (which may have been
-- introduced by a *tail or *tailall argument, which we need
-- to process before this stage so overrides don't get
-- automatically marked with footnote symbols); if par,
-- try to preserve them, but with loc this can cause
-- problems in case there are multiple dative forms
-- (stress variants) and the last one is marked with a
-- footnote symbol (occurs in грудь)
local datru_entry, datru_notes = m_table_tools.separate_notes(datru)
local dattr_entry, dattr_notes
if dattr then
dattr_entry, dattr_notes = m_table_tools.separate_notes(dattr)
end
if case == "par" then
valru, valtr = datru_entry, dattr_entry
else
valru, valtr = com.make_ending_stressed(datru_entry, dattr_entry)
datru_notes = ""
dattr_notes = ""
end
-- wrap the word in brackets so it's linked; but not if it
-- appears to already be linked
ru = rsub(ru, "^%+", "[[" .. valru .. "]]")
ru = rsub(ru, "([%[|])%+", "%1" .. valru)
ru = rsub(ru, "(%s)%+", "%1[[" .. valru .. "]]")
ru = ru .. datru_notes
-- do the translit; but it shouldn't have brackets in it
if tr or valtr then
tr = tr or com.translit_no_links(rutr[1])
valtr = valtr or com.translit_no_links(valru)
tr = rsub(tr, "^%+", valtr)
tr = rsub(tr, "(%s)%+", "%1" .. valtr)
tr = tr .. dattr_notes
end
table.insert(new_vals, {ru, tr})
end
else
table.insert(new_vals, rutr)
end
end
vals = new_vals
end
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(vals) do
local ru, tr = v[1], v[2]
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. n .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
vals = newvals
return vals
end
local function process_overrides(args, f, n)
local function process_override(case)
if args[case .. n] then
local overrides = canonicalize_override(args, case, f, n)
if not f[case] then
f[case] = {}
end
local new_overrides = {}
for _, form in ipairs(overrides) do
-- Don't consider overrides of loc/par/voc irregular since
-- they're only specified through overrides; FIXME: Theoretically
-- we could consider loc/par irregular if they don't follow the
-- expected forms; but we'd have to figure out how to eliminate
-- the preposition that may be specified
if not overridable_only_cases_set[case] and
not args.manual and
not contains_rutr_pair(f[case], form) then
local formru, formnotes = m_table_tools.separate_notes(form[1])
if formru ~= "-" then
-- don't mark an override of - as irregular, even if
-- it has an attached footnote symbol
form = com.concat_paired_russian_tr(form, {IRREGMARKER})
end
end
if case == "pauc" then
-- Internal note indicating that the form is for numbers 2, 3 and 4.
form = com.concat_paired_russian_tr(form, {paucal_marker})
end
table.insert(new_overrides, form)
end
f[case] = new_overrides
args.any_overridden[case] = true
end
end
-- do dative singular first because it will be used by loc/par
process_override("dat_sg")
-- now do the rest
for _, case in ipairs(overridable_cases) do
if case ~= "dat_sg" then
process_override(case)
end
end
-- if the nominative is overridden, use it to set the linked version unless
-- that is also specifically overridden
if args["nom_sg" .. n] and not args["nom_sg_linked" .. n] then
f.nom_sg_linked = f.nom_sg
end
if args["nom_pl" .. n] and not args["nom_pl_linked" .. n] then
f.nom_pl_linked = f.nom_pl
end
-- convert empty lists to nil to facilitate computation of accusative
-- case variants below.
for _, case in ipairs(all_cases) do
if f[case] then
if type(f[case]) ~= "table" then
error("Logic error, args[case] should be nil or table")
end
if #f[case] == 0 then
f[case] = nil
end
end
end
end
local function process_tail_args(args, f, n)
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function handle_tail_hyp(suf)
local arg, val
for _, case in ipairs(all_cases) do
arg = args[case .. "_" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args[case .. "_" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
if not rfind(case, "_pl") then
arg = args["sg" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["sg" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
else
arg = args["pl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["pl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
if not rfind(case, "nom_") and not rfind(case, "acc_") then
arg = args["obl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["obl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
end
end
handle_tail_hyp("tail")
handle_tail_hyp("hyp")
end
handle_forms_and_overrides = function(args, n, islast)
local f = args.forms
process_tail_args(args, f, n)
process_overrides(args, f, n)
local an = args.thisa
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). This logic duplicates logic in handle_overall_forms_and_overrides();
-- see long comment there. We need to duplicate the whole logic here to
-- handle words like мать-одиночка, which has an override of acc_sg1.
if not args["acc_sg_an" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_an = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_an = f.acc_sg or an == "i" and f.nom_sg or f.gen_sg or f.acc_sg_an
end
end
if not args["acc_sg_in" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_in = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_in = f.acc_sg or an == "a" and f.gen_sg or f.nom_sg or f.acc_sg_in
end
end
if not args["acc_pl_an" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_an = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_an = f.acc_pl or an== "i" and f.nom_pl or f.gen_pl or f.acc_pl_an
end
end
if not args["acc_pl_in" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_in = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_in = f.acc_pl or an == "a" and f.gen_pl or f.nom_pl or f.acc_pl_in
end
end
f.loc = f.loc or f.pre_sg
f.par = f.par or f.gen_sg
f.voc = f.voc or f.nom_sg
-- Set these in case we have plural only, in which case the
-- singular will also get set to these same values in case we are
-- a plural-only word in a singular-only expression.
f.loc_pl = f.loc_pl or f.pre_pl
f.par_pl = f.par_pl or f.gen_pl
f.voc_pl = f.voc_pl or f.nom_pl
f.count = f.count or f.gen_pl
f.pauc = f.pauc or f.gen_sg
local nu = args.thisn
-- If we have a singular-only, set the plural forms to the singular forms,
-- and vice-versa. This is important so that things work in multi-word
-- expressions that combine different number restrictions (e.g.
-- singular-only with singular/plural or singular-only with plural-only,
-- compare "St. Vincent and the Grenadines" [Сент-Винсент и Гренадины]).
if nu == "s" then
f.nom_pl_linked = f.nom_sg_linked
f.nom_pl = f.nom_sg
f.gen_pl = f.gen_sg
f.dat_pl = f.dat_sg
f.acc_pl = f.acc_sg
f.acc_pl_an = f.acc_sg_an
f.acc_pl_in = f.acc_sg_in
f.ins_pl = f.ins_sg
f.pre_pl = f.pre_sg
f.nom_pl = f.nom_sg
f.loc_pl = f.loc
f.par_pl = f.par
f.voc_pl = f.voc
elseif nu == "p" then
f.nom_sg_linked = f.nom_pl_linked
f.nom_sg = f.nom_pl
f.gen_sg = f.gen_pl
f.dat_sg = f.dat_pl
f.acc_sg = f.acc_pl
f.acc_sg_an = f.acc_pl_an
f.acc_sg_in = f.acc_pl_in
f.ins_sg = f.ins_pl
f.pre_sg = f.pre_pl
f.nom_sg = f.nom_pl
f.loc = f.loc_pl
f.par = f.par_pl
f.voc = f.voc_pl
end
end
handle_overall_forms_and_overrides = function(args)
local overall_forms = {}
for _, case in ipairs(displayable_cases) do
overall_forms[case] = concat_word_forms(args.per_word_info, case)
end
local acc_sg_overridden = args.acc_sg
local acc_pl_overridden = args.acc_pl
process_tail_args(args, overall_forms, "")
process_overrides(args, overall_forms, "")
if case_will_be_displayed(args, "pauc") then
insert_if_not(args.internal_notes, paucal_internal_note)
end
-- if IRREGMARKER is anywhere in text, remove all instances and put
-- at the end before any notes.
local function clean_irreg_marker(case, text)
if rfind(text, IRREGMARKER) then
text = rsub(text, IRREGMARKER, "")
local entry, notes = m_table_tools.separate_notes(text)
if case_will_be_displayed(args, case) then
insert_if_not(args.internal_notes, IRREGMARKER .. " Irregular.")
args.any_irreg = true
args.any_irreg_case[case] = true
end
return entry .. IRREGMARKER .. notes
else
return text
end
end
-- set final args[case] and clean up IRREGMARKER.
for _, case in ipairs(all_cases) do
args[case] = overall_forms[case]
if args[case] then
local cleaned_forms = {}
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
ru = clean_irreg_marker(case, ru)
if tr then
tr = clean_irreg_marker(case, tr)
end
table.insert(cleaned_forms, {ru, tr})
end
args[case] = cleaned_forms
end
end
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). We need to do this somewhat complicated procedure to get overrides
-- to work correctly, e.g. acc_sg overrides of feminine and neuter nouns
-- (such as мать and полслова) and gen_sg/gen_pl overrides of masculine
-- animate nouns. We also ran into an issue with words like мазло that are
-- neuter-form but can be both masculine animate (in which case the
-- acc sg inherits from the genitive) and neuter animate (in which case the
-- acc sg has the fixed ending -о, same as nominative, despite the animacy).
-- Remember also that the animate/inanimate accusative variants are the ones
-- displayed, not the plain acc_sg/acc_pl ones.
if not args.any_overridden.acc_sg_an then
if acc_sg_overridden then
args.acc_sg_an = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_an = args.acc_sg or args.a == "i" and args.nom_sg or args.gen_sg or args.acc_sg_an
end
end
if not args.any_overridden.acc_sg_in then
if acc_sg_overridden then
args.acc_sg_in = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_in = args.acc_sg or args.a == "a" and args.gen_sg or args.nom_sg or args.acc_sg_in
end
end
if not args.any_overridden.acc_pl_an then
if acc_pl_overridden then
args.acc_pl_an = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_an = args.acc_pl or args.a == "i" and args.nom_pl or args.gen_pl or args.acc_pl_an
end
end
if not args.any_overridden.acc_pl_in then
if acc_pl_overridden then
args.acc_pl_in = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_in = args.acc_pl or args.a == "a" and args.gen_pl or args.nom_pl or args.acc_pl_in
end
end
-- Try to set the values of acc_sg and acc_pl. The only time we can't is
-- when the noun is bianimate and the anim/inan values are different.
-- This is used primarily for generate_forms() and generate_multi_forms(),
-- since we don't actually display these forms.
if args.a == "a" then
args.acc_sg = args.acc_sg or args.acc_sg_an
args.acc_pl = args.acc_pl or args.acc_pl_an
elseif args.a == "i" then
args.acc_sg = args.acc_sg or args.acc_sg_in
args.acc_pl = args.acc_pl or args.acc_pl_in
else -- bianimate
args.acc_sg = args.acc_sg or m_table.deepEquals(args.acc_sg_in, args.acc_sg_an) and args.acc_sg_in or nil
args.acc_pl = args.acc_pl or m_table.deepEquals(args.acc_pl_in, args.acc_pl_an) and args.acc_pl_in or nil
end
end
-- Subfunction of concat_word_forms(), used to implement recursively
-- generating all combinations of elements from WORD_FORMS (a list, one
-- element per word, of a list of the forms for a word, each of which is a
-- two-element list of {RUSSIAN, TR}) and TRAILING_FORMS (a list of forms, the
-- accumulated suffixes for trailing words so far in the recursion process,
-- again where each form is a two-element list {RUSSIAN, TR}). Each time we
-- recur we take the last FORMS item off of WORD_FORMS and to each form in
-- FORMS we add all elements in TRAILING_FORMS, passing the newly generated
-- list of items down the next recursion level with the shorter WORD_FORMS.
-- We end up returning a list of concatenated forms, where each list item
-- is a two-element list {RUSSIAN, TR}.
local function concat_word_forms_1(word_forms, trailing_forms)
if #word_forms == 0 then
local retforms = {}
for _, form in ipairs(trailing_forms) do
local ru, tr = form[1], form[2]
-- Remove <insa> and <insb> markers; they've served their purpose.
ru = rsub(ru, "<ins[ab]>", "")
tr = tr and rsub(tr, "<ins[ab]>", "")
table.insert(retforms, {ru, tr})
end
return retforms
else
local last_form_info = table.remove(word_forms)
local last_forms, joiner = last_form_info[1], last_form_info[2]
local new_trailing_forms = {}
for _, form in ipairs(last_forms) do
for _, trailing_form in ipairs(trailing_forms) do
-- If form to prepend is empty, don't add the joiner; this
-- is principally used in overall overrides, where we stuff
-- the entire override into the last word
local full_form = form[1] == "" and trailing_form or
com.concat_paired_russian_tr(form,
com.concat_paired_russian_tr(joiner, trailing_form),
"movenotes")
if rfind(full_form[1], "<insa>") and rfind(full_form[1], "<insb>") then
-- REJECT! So we don't get mixtures of the two feminine
-- instrumental singular endings.
else
table.insert(new_trailing_forms, full_form)
end
end
end
return concat_word_forms_1(word_forms, new_trailing_forms)
end
end
-- Generate a list of overall forms by concatenating the per-word forms.
-- PER_WORD_INFO comes from args.per_word_info and is a list of
-- WORD_INFO items, one per word, each of which a two element list of
-- WORD_FORMS (a table listing the forms for each case) and JOINER (a string).
-- We loop over all possible combinations of elements from each word's list
-- of forms for the given case; this requires recursion.
concat_word_forms = function(per_word_info, case)
local word_forms = {}
-- Gather the appropriate word forms. We have to recreate this anew
-- because it will be destructively modified by concat_word_forms_1().
for _, word_info in ipairs(per_word_info) do
table.insert(word_forms, {word_info[1][case], word_info[2]})
end
-- We need to start the recursion with the second parameter containing
-- one blank element rather than no elements, otherwise no elements
-- will be propagated to the next recursion level.
return concat_word_forms_1(word_forms, {{""}})
end
local accel_forms = {
nom_sg = "nom|s",
nom_sg_linked = "nom|s",
nom_pl = "nom|p",
nom_pl_linked = "nom|p",
gen_sg = "gen|s",
gen_pl = "gen|p",
dat_sg = "dat|s",
dat_pl = "dat|p",
acc_sg_an = "an|acc|s",
acc_pl_an = "an|acc|p",
acc_sg_in = "in|acc|s",
acc_pl_in = "in|acc|p",
ins_sg = "ins|s",
ins_pl = "ins|p",
pre_sg = "pre|s",
pre_pl = "pre|p",
loc = "loc|s",
loc_pl = "loc|p",
voc = "voc|s",
voc_pl = "voc|p",
par = "par|s",
par_pl = "par|p",
count = "count form",
pauc = "pau",
}
-- Make the table
make_table = function(args)
local data = {}
data.after_title = " " .. args.heading
data.number = args.nonumber and "" or numbers[args.n]
local lemma_forms = args[args.n == "p" and "nom_pl" or "nom_sg"]
data.lemma = nom.show_form(args.explicit_lemma and {{args.explicit_lemma, args.explicit_lemmatr}} or
args[args.n == "p" and "nom_pl_linked" or "nom_sg_linked"], "lemma", nil, nil)
data.title = args.title or format(args.old and old_title_temp or title_temp, data)
local sg_an_in_equal = m_table.deepEquals(args.acc_sg_an, args.acc_sg_in)
local pl_an_in_equal = m_table.deepEquals(args.acc_pl_an, args.acc_pl_in)
for _, case in ipairs(displayable_cases) do
local accel_form = accel_forms[case]
if not accel_form then
error("Something wrong, can't find accelerator form for " .. case)
end
if (sg_an_in_equal and (case == "acc_sg_an" or case == "acc_sg_in") or
pl_an_in_equal and (case == "acc_pl_an" or case == "acc_pl_in")) then
accel_form = rsub(accel_form, "^[ai]n|", "")
end
if args.n == "p" then
accel_form = rsub(accel_form, "|p$", "")
end
data[case] = nom.show_form(args[case], false, accel_form, lemma_forms, "remove monosyllabic accents only lemma")
end
local temp = nil
if args.n == "s" then
data.nom_x = data.nom_sg
data.gen_x = data.gen_sg
data.dat_x = data.dat_sg
data.acc_x_an = data.acc_sg_an
data.acc_x_in = data.acc_sg_in
data.ins_x = data.ins_sg
data.pre_x = data.pre_sg
if sg_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
elseif args.n == "p" then
data.nom_x = data.nom_pl
data.gen_x = data.gen_pl
data.dat_x = data.dat_pl
data.acc_x_an = data.acc_pl_an
data.acc_x_in = data.acc_pl_in
data.ins_x = data.ins_pl
data.pre_x = data.pre_pl
data.par = data.par_pl
data.loc = data.loc_pl
data.voc = data.voc_pl
if pl_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
else
if pl_an_in_equal then
temp = "both_numbers"
elseif sg_an_in_equal then
temp = "both_numbers_split_animacy_plural_only"
else
temp = "both_numbers_split_animacy"
end
end
for _, extra_case in ipairs({
{"par", "partitive"},
{"loc", "locative"},
{"voc", "vocative"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "s" and args.n ~= "p" and args.any_overridden[case .. "_pl"] then
if not args.any_overridden[case] then
data[case] = ""
end
template = extra_case_template_with_plural
elseif args.n ~= "p" and args.any_overridden[case] or args.n == "p" and args.any_overridden[case .. "_pl"] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
for _, extra_case in ipairs({
{"count", "count form"},
{"pauc", "paucal"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "p" and args.any_overridden[case] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
local notes = get_arg_chain(args, "notes", "notes")
local all_notes = {}
for _, note in ipairs(args.internal_notes) do
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
for _, note in ipairs(notes) do
-- Here too.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
data.notes = table.concat(all_notes, "<br />")
data.notes_clause = data.notes ~= "" and format(notes_template, data) or ""
return format(templates[temp], data)
end
function extra_case_template(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
|
|-]===]):format(colspan)
end
function extra_case_template_with_plural(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
| {\op}{case}_pl{\cl}
|-]===]):format(colspan)
end
notes_template = [===[
<div style="width:100%;text-align:left;background:var(--wikt-palette-lightblue, #d9ebff);">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame" data-toggle-category="လဟုတ်စှ်ေ" style="max-width:MINWIDTHem">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);">{title}<span style="font-weight:normal;">{after_title}</span> </div>
<div class="NavContent">
{\op}| style="table-layout:fixed; text-align:center; max-width:MINWIDTHem; width:100%;" class="inflection inflection-table"
|- class="rowgroup"
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[|-{par_clause}{loc_clause}{voc_clause}{count_clause}{pauc_clause}
|{\cl}{notes_clause}</div></div></div>]===]
end
templates["both_numbers"] = template_prelude("45") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_sg_in}
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy_plural_only"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 rowspan=2 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["one_number"] = template_prelude("30") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
templates["one_number_split_animacy"] = template_prelude("35") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| {acc_x_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
return export
s9jqvgkhg1l24cjhjm1g39ey7w3gt3s
399801
399800
2026-07-21T03:09:42Z
Intobesa.bot
1035
Bot: ပွမကၠာဲစုတ်ယၟုနူဘာသာအၚ်္ဂလိက်
399801
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
nouns.
Author: Benwing, rewritten from early version by Wikitiki89
Form of arguments: One of the following:
1. LEMMA|DECL|PLSTEM (all arguments optional)
2. ACCENT|LEMMA|DECL|PLSTEM (all arguments optional)
3. multiple sets of arguments separated by the literal word "or"
Arguments:
ACCENT: Accent pattern (a b c d e f b' d' f' f''). Multiple values can
be specified, separated by commas. If omitted, defaults to a or b
depending on the position of stress on the lemma or
explicitly-specified declension.
LEMMA: Lemma form (i.e. nom sg or nom pl), with appropriately-placed
stress; or the stem, if an explicit declension is specified
(in this case, the declension usually looks like an ending, and
the stem is the portion of the lemma minus the ending). In the
first argument set (i.e. first set of arguments separated
by "or"), defaults to page name; in later sets, defaults to lemma
of previous set. A plural form can be given, and causes argument
n= to default to n=p (plural only). Normally, an accent is
required if multisyllabic, and unaccented monosyllables with
automatically be stressed; prefix with * to override both behaviors.
DECL: Declension field. Normally omitted to autodetect based on the
lemma form; see below.
PLSTEM: special plural stem (defaults to stem of lemma)
Additional named arguments:
a: animacy (a/an/anim = animate, i/in/inan = inanimate, b/bi/both/ai = both
(listing animate first in the headword), ia = both (listing inanimate
first in the headword), otherwise inanimate)
n: number restriction (p = plural only, s = singular only, b = both;
defaults to both unless the lemma is plural, in which case it
defaults to plural only)
CASE_NUM or acc_NUM_ANIM or par/loc/voc: override (or multiple
values separated by commas) for case/number combination;
forms auto-linked; can have raw links in it, can have an
ending "note" (*, +, 1, 2, 3, etc.)
pltail: Specify something (usually a * or similar) to attach to
the end of the last plural form when there's more than one. Used in
conjunction with notes= to indicate that alternative plural forms
are obsolete, poetic, etc.
pltailall: Similar pltail= but attaches to all plural forms.
Typically used in conjunction with notes= to make a comment about
the plural as a whole (e.g. it's mostly hypothetical, rare and
awkward, etc.).
sgtail, sgtailall: Same as pltail=, pltailall= but for the singular.
obltail, obltailall: Same as pltail=, pltailall= but for oblique cases
(not the nominative or accusative).
CASE_NUM_tail: Attach the argument to the end of the last form
(whether there's one or more than one) for the particular
case/number combination. Note that this doesn't work quite like
pltail= or sgtail= in that it doesn't skip adding the argument
when there's only one form.
CASE_NUM_tailall: Attach the argument to the end of all forms
specified for the particular case/number combination. Similar to
pltailall= or sgtailall=.
suffix: Add a suffix such as ся to all forms.
prefix: Add a prefix to all forms.
plhyp, plhypall, CASE_NUM_hyp, etc.: Same as pltail, pltailall,
CASE_NUM_tal, etc. but specify that the marked forms are
mostly hypothetical or rare/awkard. Generally you will want
plhypall=y to mark the plural as hypothetical.
Per word named arguments:
All of the above named arguments have per-word variants, e.g.
a1, a2, ...; n1, n2, ...; CASE_NUM1, CASE_NUM2, ...;
pltail1, pltail2, ...; etc. These apply to the individual words of a
form.
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
par: partitive
loc: locative
voc: vocative
Number abbreviations:
sg: singular
pl: plural
Animacy abbreviations:
an: animate
in: inanimate
Declension field:
One of the following for regular nouns:
(blank)
GENDER
-VARIANT
GENDER-VARIANT
$
DECLTYPE
DECLTYPE/DECLTYPE
(also, can append various special-case markers to any of the above)
Or one of the following for adjectival nouns:
+
+ь
$
+short, +mixed or +proper
+DECLTYPE
GENDER if present is m, f, n or 3f; for regular nouns, required if the
lemma ends in -ь or is plural, ignored otherwise. 3f is the same
as f but in the case of a plural lemma in -и, detects a
third-declension feminine with singular in -ь rather than a
first-declension feminine with singular in -а or -я.
VARIANT is one way of requesting variant declensions (see also special
case (1) for variant nom pls, and special case (2) for variant
gen pls). The currently allowed values are -ья (will select a
mixed declension that has some normal declension in its singular
and the -ья plural declension); -ин (for animate masculine nouns
in -ин with plural in -е -- note that this is autodetected in the
majority of cases where the ending in -янин or -анин); -ишко
(used for inanimate neuter-form diminutive masculine nouns in
-ишко [also сараю́шко] with nom pl -и and colloquial feminine-ending
alternants in some singular cases); -ище (similar to -ишко but
used for *animate* augmentative masculine neuter-form nouns in
-ище). Variants -ишко and -ище must be given with with special
case (1).
$ is indeclinable words. It is principally useful in multiword
expressions where some of the words are indeclinable.
DECLTYPE is an explicit declension type. Normally you shouldn't use
this, and should instead let the declension type be autodetected
based on the ending, supplying the appropriate hint if needed
(gender for regular nouns, +ь for adjectives). If provided, the
declension type is usually the same as the ending, and if present,
the lemma field should be just the stem, without the ending.
Possibilities for regular nouns are (blank) or # for hard-consonant
declension, а, я, о, е or ё, е́, й, ья, ье or ьё, ь-m, ь-f,
ин, ёнок or онок or енок, ёночек or оночек or еночек, мя,
-а or #-а, ь-я, й-я, о-и or о-ы, -ья or #-ья, $ (indeclinable).
Old-style (pre-reform) declensions use ъ instead of (blank), ъ-а
instead of -а, ъ-ья instead of -ья, and инъ, ёнокъ/онокъ/енокъ,
ёночекъ/оночекъ/еночекъ instead of the same without terminating ъ.
The declensions can also be written with an accent on them; this
chooses the same declension (except for е vs. е́), but causes
ACCENT to default to pattern b instead of a.
For adjectival nouns, you should normally supply just + and let
the ending determine the declension; supply +ь in the case of a
possessive adjectival noun in -ий, which have an extra -ь- in
most endings compared with normal adjectival nouns in -ий, but
which can't be distinguished based on the nominative singular.
You can also supply +short, +mixed or +proper, which constrains
the declension appropriately but still autodetects the
gender-specific and stress-specific variant. If you do supply
a specific declension type, as with regular nouns you need to
omit the ending from the lemma field and supply just the stem.
Possibilities are +ый, +ое, +ая, +ій, +ее, +яя, +ой, +о́е, +а́я,
+ьій, +ье, +ья, +-short or +#-short (masc), +о-short,
+о-stressed-short or +о́-short, +а-short, +а-stressed-short or
+а́-short, and similar for -mixed and -proper (except there aren't
any stressed mixed declensions).
DECLTYPE/DECLTYPE is used for nouns with one declension in the
singular and a different one in the plural, for cases that
PLVARIANT and special case (1) below don't cover.
Special-case markers:
(1) for Zaliznyak-style alternative nominative plural ending:
-а or -я for masculine, -и or -ы for neuter
(2) for Zaliznyak-style alternative genitive plural ending:
-ъ/none for masculine, -ей for feminine, -ов(ъ) for neuter,
-ей for plural variant -ья
* for reducibles (nom sg or gen pl has an extra vowel before the
final consonant as compared with the stem found in other cases)
;ё for Zaliznyak-style alternation between last е in stem and ё
TODO:
1. Multi-word issues:
-- FIXME: Make sure internal_notes handled correctly; we may run into issues
with multiple internal notes from different words, if we're not careful
to use different footnote symbols for each type of footnote (which we
don't do currently). [NOT DONE, MAY NOT DO]
-- Handling default lemma: With multiple words, we should probably split
the page name on spaces and default each word in turn [NOT DONE, MAY
NOT DO]
2a. FIXME: For -ишко diminutives and -ище augmentatives, should add an
appropriate category of some sort (currently marked by colloqfem= in
category).
2b. FIXME: Adding a note to dat_sg also adds it to loc_sg when it exists;
seems wrong. See луг.
2c. FIXME: When you have both d' and f in feminines and you use sgtail=*,
you get two *'s. See User:Benwing2/test-ru-noun-debug.
3. ADJECTIVE FIXMES:
3a. FIXME: Change calls to ru-adj11 to use the new proper name support in
ru-adjective.
3b. FIXME: Test that omitting a manual form in ru-adjective leaves the form as
a big dash.
3c. FIXME: какой-либо and какой-то display genitives with translit -go
instead of -vo. To fix this properly requires implementing real
manual translit for adjectives.
3d. FIXME: Implement real manual translit for adjectives.
5. [FIXME: Consider adding an indicator in the header line when the ё/e
alternation occurs. This is a bit tricky to calculate: If special case
;ё is given, but also if ё occurs in the stem and the accent pattern is
as follows -- for sg-only, b' d' f' f'', also b d f if the noun is masc
or 3rd-decl fem (i.e. nom-sg ending is non-syllabic); for pl-only,
e f f' f'', also b b' c if the gen pl is non-syllabic; for sg/pl,
any but a or b, also b if either nom sg or gen pl is non-syllabic. But
it gets more complicated due to overrides. An alternative is to check
all forms to see if ё is present in some but not all; but this is
tricky also because e.g. reducibles frequently have ё/null alternation,
which doesn't count, and some endings have е or ё in them, which also
doesn't count. If we were to do it this way, we'd have to (a) count
the number of е's in the form(s) with ё and verify that there's at least
one form without ё and with one more е than in the form(s) with ё
(and it gets trickier if different forms with ё have different numbers of
е in them, although that is probably rare); and (b) ignore the appropriate
endings (the best way to do this would probably be to look at the actual
suffixes that were generated in args.suffixes and chop off any matching
ending in the actual form(s), but also chop off final -е/ё, as well as
-ев(ъ)/-ёв(ъ)/-ей/-ёй in the gen pl, which is frequently overridden,
unless perhaps the stem ends in the same way). It'd probably not
possible to do this in a 100% foolproof way but can be "good enough" for
nearly all circumstances.] [MIGHT BE TOO MUCH WORK]
6. HEADWORD FIXMES:
6a. FIXME: In ru-headword, create a category for words whose gender doesn't
match the form. (This is easy to do for ru-noun+ but harder for ru-noun.
We would need to do limited autodetection of the ending: for singulars,
-а/я should be feminine, -е/о/ё should be neuter, -ь should be masculine
or feminine, anything else should be masculine; for plurals, -и/ы should
be masculine or feminine, -а/я should be neuter except that -ія can be
feminine or neuter due to old-style adjectival pluralia tantum nouns,
anything else can be any gender.)
6b. FIXME: Recognize indeclinable nouns and indicate as indeclinable. Probably
should work by checking the case forms to see if they're the same.
9. FIXME: Change stress-pattern detection and overriding to happen inside of
looping over the two parts of a slash decl. Requires that the loop over
the two parts happen outside of the loop over stress patterns. Requires
that the category code get split into two parts, one to handle combined
singular/plural categories that goes outside the two loops, and one to
handle everything else that goes inside the two loops.
10. FIXME: override_matches_suffix() had a free variable reference to ARGS
in it, which should have triggered an error whenever there was a nom_sg or
nom_pl override but didn't. Is there an error causing this never to be
called? Check.
11a. FIXME: In a multiword lemma, using loc2=+ causes only the second word
to get linked instead of the whole expression. Same for par2=+, voc2=+.
11b. FIXME: Using loc=+ with a multiword lemma should do the right thing, same
as if locN=+ is specified for each individual word. Instead it generates
the locative as a whole from the dative, which fails e.g. if some of the
words are adjectival. Same for par=+, voc=+.
13. Multi-word issues:
-- Setting n=pl when auto-detecting a plural lemma. How does that interact
with multi-word stuff? (DONE)
-- compute_heading() -- what to do with multiple words? I assume we should
display info on the first noun (non-indeclinable, non-adjectival), and
on the first adjectival word otherwise, and finally on an indeclinable word (DONE)
-- args.genders -- it should presumably come from the same word as is used
in compute_heading(); but we should allow the overall gender to be
overridden, at least in ru-noun+ (DONE)
-- Bug in args.suffix: Gets added to every word in attach_with() and then
again at the end, after pltail and such. Needs to be added to the
last word only, before pltail. Need also suffixN for individual words.
(DONE, NEEDS TESTING)
-- Should have ..N versions of pltail and variants. (DONE, NEEDS TESTING)
-- Need to handle overrides of acc_sg, acc_pl (DONE)
-- Overrides of nom_sg/nom_pl should also override acc_sg/acc_pl if it
was originally empty and the animacy is inanimate; similarly for
gen_sg/gen_pl and animates; this needs to work both for per-word and
overall overrides. (DONE)
-- do_generate_forms(_multi) need to run part of make_table(), enough to
combine all per_word_info into single lists of forms and store back
into args[case]. (DONE, NEEDS TESTING)
-- In generate_forms, should probably check if a=="i" and only return
acc_sg_in as acc_sg=; or if a=="a" and only return acc_sg_an as acc_sg=;
in old/new comparison code, do something similar, also when a=="b"
check if acc_sg_in==acc_sg_an and make it acc_sg; when a=="b" and the
_in and _an variants are different, might need to ignore them or check
that acc_sg_in==nom_sg and acc_sg_an==gen_sg; similarly for _pl
(DONE, NEEDS TESTING)
-- Need to test with multiple words! [DONE]
-- Current handling of <adj> won't work properly with multiple words;
will need to translate word-by-word in that case (should be solved by
manual-translit branch) [DONE]
14. In multiple-words branch, fix ru-decl-noun-multi so it recognizes
things like *, (1), (2) and ; without the need for a separator. Consider
using semicolon as a separator, since we already use it to separate ё
from a previous declension. Maybe use $ or ~ for an indeclinable word; don't
use semicolon. [IMPLEMENTED. NEED TO TEST.]
16. [Consider having ru-noun+ treat par= as a second genitive in
the headword, as is done with край] [WON'T DO]
17. [FIXME: Consider removing slash patterns and instead handling them by
allowing additional declension flags 'sg' and 'pl'. This simplifies the
various special cases caused by slash declensions. It would also be
possible to remove the special plural stem, which would get rid of more
special cases. On the other hand, it makes it more complicated to support
plural variant -ья with all singular types, and the category code that
displays things like "နာမ်ရုဿျှာဂမၠိုၚ် with singular -X and plural -Y"
also gets more complicated, and there's something convenient and intuitive
about plural stems, and slash declensions are also convenient and at least
somewhat intuitive. One possibility is to externally allow slash
declensions and special plural stems and rewrite them internally to
separate stems with 'sg' and 'pl' declension flags; but there are still
the two coding issues mentioned above.]
18. [FIXME: Consider redoing slash patterns so they operate at the outer
level, i.e. things like special cases apply separately in the singular
and plural part of the slash pattern.]
19. In ru-noun, don't recognize -а with m as plural unless (1)
or n=pl is also given, because there are masculine words with the
feminine ending. Check using the test code whether this changes
anything. Also check if there are other similar cases (neuter with
-и isn't parallel because -и is always plural). [IMPLEMENTED. NEED TO TEST.]
19a. Internal notes weren't propagated properly from adjectives.
[IMPLEMENTED. NEED TO TEST.]
19b. Add support for -ишко and -ище variants (p. 74 of Z),
which conversationally and/or colloquially have feminine endings in
certain cases. [IMPLEMENTED. NEED TO TEST. MAKE SURE THE INTERNAL NOTES
APPEAR.]
19d. For masculine animate neuter-form nouns, the accusative singular
ends in -а (-я soft) instead of -о. [IMPLEMENTED. NEED TO TEST.
NOTE: Currently this variant only can be selected using new-style
arguments where the gender can be given. Perhaps we should consider
allowing gender to be specified with old-style explicit declensions.]
21. Put back gender hints for pl adjectival nouns; used by ru-noun+.
[IMPLEMENTED. NEED TO TEST.]
23. Mixed and proper-noun adjectives have built-in notes. We need to
handle those notes with an "internal_notes" section similar to what is used
in the adjective module. [IMPLEMENTED. NEED TO TEST.]
24. Adjective detection code here needs to work the same as for the
adjective module, in particular in the handling of short, stressed-short,
mixed, proper, stressed-proper. [IMPLEMENTED. NEED TO TEST.]
25. Consider simplifying plural-variant code to only allow -ья as a
plural variant [and maybe even change that to be something like (1')].
[IMPLEMENTED REDUCTION OF PLURAL VARIANTS TO -ья; PLURAL-VARIANT CODE
STILL COMPLEX, THOUGH. NEED TO TEST.]
26. Automatically superscript *, numbers and similar things at the
beginning of a note. Also do this in adjective module. [IMPLEMENTED.
NEED TO TEST.]
28. Make the check for multiple stress patterns (categorizing/tracking)
smarter, to keep a list of them and check at the end, so we handle
multiple stress patterns specified through different arg sets.
[IMPLEMENTED; NEED TO TEST.]
29. More sophisticated handling of user-requested plural variant vs. special
case (1) vs. plural-detected variant. [IMPLEMENTED. NEED TO TEST FURTHER.]
30. Solution to ambiguous plural involving gender spec "3f". [IMPLEMENTED;
NEED TO TEST. Use запчасти, новости.]
33. With pluralia tantum adjectival nouns, we don't know the gender.
By default we assume masculine (or feminine for old-style -ія nouns) and
currently this goes into the category, but shouldn't. [IMPLEMENTED.]
39. [Eventually: Even with decl type explicitly given, the full stem with
ending should be included.] [MAY NEVER IMPLEMENT]
40. [Get error "Unable to dereduce" with strange noun ва́йя, what should
happen?] [WILL NOT FIX; USE AN OVERRIDE]
41. In творог, module generates partitive творогу́ when it should copy the
dative творогу́,тво́рогу. (DONE)
42. [[груз 200]] doesn't work. Interprets 200 as a footnote symbol.
43. When converting е -> ё not after cons and with translit, we should
convert e -> o to avoid double j. (DONE)
44. FIXME: In ро́вня/ровня́, similarly with неровня, marks genitive plural
ровня́ as irregular even though it isn't. (NOT OUR ERROR; THE DECLENSIONS
OF THESE NOUNS MARKED THE ENDING-STRESSED VARIANTS WITH (2).)
]=]--
local m_utilities = require("Module:utilities")
local m_table = require("Module:table")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local m_ru_adj = require("Module:ru-adjective")
local m_str_utils = require("Module:string utilities")
local scriptutils = require("Module:script utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
local Latn = require("Module:scripts").getByCode("Latn")
local format = m_str_utils.format
local rfind = m_str_utils.find
local rsubn = m_str_utils.gsub
local rmatch = m_str_utils.match
local rsplit = m_str_utils.split
local u = m_str_utils.char
local ulower = m_str_utils.lower
local usub = m_str_utils.sub
local ulen = m_str_utils.len
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same. Eventually consider removing this;
-- but useful as new code is created.
local test_new_ru_noun_module = false
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local DIA = u(0x0308) -- diaeresis = ̈
local PSEUDOCONS = u(0xFFF2) -- pseudoconsonant placeholder, matching ru-common
local IRREGMARKER = "△"
local HYPMARKER = "⟐"
local paucal_marker = "*"
local paucal_internal_note = "* Used with the numbers 1.5, 2, 3, 4 and higher numbers after 20 ending in 2, 3, and 4."
-- text class to check lowercase arg against to see if Latin text embedded in it
local latin_text_class = "[a-zščžěáéíóúýàèìòùỳâêîôûŷạẹịọụỵȧėȯẏ]"
-- Forward functions
local generate_forms_1
local determine_decl
local handle_forms_and_overrides
local handle_overall_forms_and_overrides
local concat_word_forms
local make_table
local detect_adj_type
local detect_stress_pattern
local override_stress_pattern
local determine_stress_variant
local determine_stem_variant
local is_reducible
local is_dereducible
local add_bare_suffix
local attach_stressed
local do_stress_pattern
local canonicalize_override
-- 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
-- version of rfind() that lowercases its string first, for case-insensitive matching
local function rlfind(term, foo)
return rfind(ulower(term), foo)
end
local function track(page)
m_debug.track("ru-noun/" .. page)
return true
end
-- version of m_table.insertIfNot() that makes sure 'false' doesn't get inserted by mistake.
local function insert_if_not(foo, bar)
assert(bar ~= false)
m_table.insertIfNot(foo, bar)
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-- FIXME: Move to utils
-- Iterate over a chain of parameters, FIRST then PREF2, PREF3, ...,
-- inserting into LIST (newly created if omitted). Return LIST.
local function get_arg_chain(args, first, pref, list)
if not list then
list = {}
end
local val = args[first]
local i = 2
while val do
table.insert(list, val)
val = args[pref .. i]
i = i + 1
end
return list
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
local function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
local function rutr_pairs_equal(term1, term2)
local ru1, tr1 = term1[1], term1[2]
local ru2, tr2 = term2[1], term2[2]
local ru1entry, ru1notes = m_table_tools.separate_notes(m_links.remove_links(ru1))
local ru2entry, ru2notes = m_table_tools.separate_notes(m_links.remove_links(ru2))
if ru1entry ~= ru2entry then
return false
end
local tr1entry, tr1notes
local tr2entry, tr2notes
if tr1 then
tr1entry, tr1notes = m_table_tools.separate_notes(tr1)
end
if tr2 then
tr2entry, tr2notes = m_table_tools.separate_notes(tr2)
end
if tr1entry == tr2entry then
return true
elseif type(tr1entry) == type(tr2entry) then
return false
else
tr1entry = tr1entry or com.translit_no_links(ru1entry)
tr2entry = tr2entry or com.translit_no_links(ru2entry)
return tr1entry == tr2entry
end
end
local function contains_rutr_pair(list, pair)
for _, item in ipairs(list) do
if rutr_pairs_equal(item, pair) then
return true
end
end
return false
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
args[pname] = ine(param)
end
return args
end
-- Old-style declensions.
local declensions_old = {}
-- New-style declensions; computed automatically from the old-style ones,
-- for the most part.
local declensions = {}
-- Internal notes for old-style declensions.
local internal_notes_table_old = {}
-- Same for new-style declensions.
local internal_notes_table = {}
-- Category and type information corresponding to declensions: These may
-- contain the following fields: 'singular', 'plural', 'decl', 'hard', 'g',
-- 'suffix', 'gensg', 'irregpl', 'alt_nom_pl', 'cant_reduce', 'ignore_reduce',
-- 'stem_suffix'.
--
-- 'singular' is used to construct a category of the form
-- "နာမ်ရုဿျှာဂမၠိုၚ် SINGULAR". If omitted, a category is constructed of the
-- form "နာမ်ရုဿျှာဂမၠိုၚ် ending in -ENDING", where ENDING is the actual
-- nom sg ending shorn of its acute accents; or "နာမ်ရုဿျှာဂမၠိုၚ် ending
-- in suffix -ENDING", if 'suffix' is true. The value of SINGULAR can be
-- one of the following: a single string, a list of strings, or a function,
-- which is passed one argument (the value of ENDING that would be used to
-- auto-initialize the category), and should return a single string or list
-- of strings. Such a category is only constructed if 'gensg' is true.
--
-- 'plural' is analogous but used to construct a category of the form
-- "နာမ်ရုဿျှာဂမၠိုၚ် with PLURAL", and if omitted, a category is constructed
-- of the form "နာမ်ရုဿျှာဂမၠိုၚ် with plural -ENDING", based on the actual
-- nom pl ending shorn of its acute accents. Currently no plural category
-- is actually constructed.
--
-- In addition, a category may normally constructed from the combination of
-- 'singular' and 'plural', appropriately defaulted; e.g. if both are present,
-- the combined category will be "နာမ်ရုဿျှာဂမၠိုၚ် SINGULAR with PLURAL" and
-- if both are missing, the combined category will be
-- "နာမ်ရုဿျှာဂမၠိုၚ် ending in -SGENDING with plural -PLENDING" (or
-- "နာမ်ရုဿျှာဂမၠိုၚ် ending in suffix -SGENDING with plural -PLENDING" if
-- 'suffix' is true). Note that if either singular or plural or both
-- specifies a list, looping will occur over all combinations. Such a
-- category is constructed only if 'irregpl' or 'alt_nom_pl' or 'suffix'
-- is true or if the declension class is a slash class.
--
-- 'decl' is "1st", "2nd", "3rd" or "indeclinable"; 'hard' is "hard", "soft"
-- or "none"; 'g' is "m", "f", "n" or "none"; these are all traditional
-- declension categories.
--
-- If 'suffix' is true, the declension type includes a long suffix
-- added to the string that itself undergoes reducibility and such, and so
-- reducibility cannot occur in the stem minus the suffix. Categories will
-- be created for the suffix.
--
-- 'alt_nom_pl' indicates that the declension has an alternative nominative
-- plural (corresponding to Zaliznyak's special case 1; compare special case 2
-- for alternative genitive plural). 'irregpl' indicates that the entire
-- plural is irregular.
--
-- In addition to the above categories, additional more specific categories
-- are constructed based on the final letter of the stem, e.g.
-- "Russian velar-stem 1st-declension hard nouns". See calls to
-- com.get_stem_trailing_letter_type(). 'stem_suffix', if present, is added to
-- the end of the stem when get_stem_trailing_letter_type() is called.
-- This is the only place that 'stem_suffix' is used. This is for use with
-- the '-ья' and '-ье' declension types, so that the trailing letter is
-- 'ь' and not whatever precedes it.
--
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
-- Category/type info corresponding to old-style declensions; see above.
local declensions_old_cat = {}
-- Category/type info corresponding to new-style declensions. Computed
-- automatically from the old-style ones, for the most part. Same format
-- as the old-style ones.
local declensions_cat = {}
-- Table listing aliases of old-style declension classes.
local declensions_old_aliases = {}
-- Table listing aliases of new-style declension classes; computed
-- automatically from the old-style ones.
local declensions_aliases = {}
local stress_patterns = {}
-- Set of patterns with ending-stressed genitive plural.
local ending_stressed_gen_pl_patterns = {}
-- Set of patterns with ending-stressed prepositional singular.
local ending_stressed_pre_sg_patterns = {}
-- Set of patterns with ending-stressed dative singular.
local ending_stressed_dat_sg_patterns = {}
-- Set of patterns with all singular forms ending-stressed.
local ending_stressed_sg_patterns = {}
-- Set of patterns with all plural forms ending-stressed.
local ending_stressed_pl_patterns = {}
local declinable_cases_except_accusative = {
"nom_sg", "gen_sg", "dat_sg", "ins_sg", "pre_sg",
"nom_pl", "gen_pl", "dat_pl", "ins_pl", "pre_pl",
}
local accusative_cases_unsplit_animacy = {
"acc_sg", "acc_pl",
}
local accusative_cases_split_animacy = {
"acc_sg_an", "acc_sg_in", "acc_pl_an", "acc_pl_in",
}
local lemma_linked_cases = {
"nom_sg_linked", "nom_pl_linked",
}
local overridable_only_cases = {
"par", "loc", "voc", "par_pl", "loc_pl", "voc_pl", "count", "pauc",
}
local overridable_only_cases_set = m_table.listToSet(overridable_only_cases)
-- List of all cases that are declined normally.
local decl_cases = m_table.append(declinable_cases_except_accusative, accusative_cases_unsplit_animacy)
-- List of all cases that can be overridden (includes all cases except the "linked" lemma case variants). Also
-- currently the same as the cases returned by export.generate_forms().
local overridable_cases = m_table.append(decl_cases, accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases that can be displayed (includes all cases except plain accusatives).
local displayable_cases = m_table.append(declinable_cases_except_accusative, lemma_linked_cases,
accusative_cases_split_animacy, overridable_only_cases)
-- List of all cases, including those that are declined normally (nom/gen/dat/acc/ins/pre sg and pl), plus
-- animate/inanimate accusative variants (computed automatically as appropriate from the previous cases), plus
-- additional overridable cases (loc/par/voc and plural), plus the "linked" lemma case variants used in ru-noun+
-- headwords (nom_sg_linked, nom_pl_linked, whose values come from nom_sg and nom_pl but may have additional embedded
-- links if they were given in the lemma).
local all_cases = m_table.append(overridable_cases, lemma_linked_cases)
local function english_case_description(case)
if case == "par" or case == "loc" or case == "voc" then
-- For historical reasons, the singular of these cases doens't include "_sg" in their code.
case = case .. "_sg"
end
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
par="partitive", loc="locative", voc="vocative",
count="count form", pauc="paucal form",
})
engcase = rsub(engcase, "(_[a-z]*)", {
_sg=" singular", _pl=" plural",
_an="", _in="",
--_an=" animate", _in=" inanimate"
})
return engcase
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
-- FIXME! Move below the main code
-- FIXME!! Consider deleting most of this tracking code once we've enabled
-- all the categories. Note that some of the tracking categories aren't
-- completely redundant; e.g. we have tracking pages that combine decl and
-- stress classes, such as "а/a" or "о-и/d'", which are more or less
-- equivalent to stem/gender/stress categories, but we also have the same
-- prefixed by "reducible-stem/" for reducible stems.
local function tracking_code(stress, orig_decl, decl, args, n, islast)
assert(orig_decl)
assert(decl)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
if orig_decl == decl then
orig_decl = nil
end
if args.notes then
track("notes")
end
local function all_pl_irreg()
track("irreg")
for _, case in ipairs(overridable_cases) do
if rfind(case, "_pl") then
track("irreg/" .. case)
end
end
end
local function track_prefix(prefix)
local function dotrack(suf)
track(prefix .. suf)
end
dotrack(stress)
dotrack(decl)
dotrack(decl .. "/" .. stress)
if orig_decl then
dotrack(orig_decl)
dotrack(orig_decl .. "/" .. stress)
end
for _, hint_type in ipairs(hint_types) do
dotrack(hint_type)
dotrack(decl .. "/" .. hint_type)
if orig_decl then
dotrack(orig_decl .. "/" .. hint_type)
end
end
end
track_prefix("")
if args.reducible then
track("reducible-stem")
track_prefix("reducible-stem/")
end
if rlfind(args.stem, "и́?н$") and (decl == "" or decl == "#") then
track("irregular-in")
end
if args.pltail then
track("pltail")
end
if args.sgtail then
track("sgtail")
end
if args.pltailall then
track("pltailall")
end
if args.sgtailall then
track("sgtailall")
end
if args.pl ~= args.stem then
track("irreg-pl-stem")
track("irreg")
end
if args.alt_gen_pl then
track("alt-gen-pl")
track("irreg")
track("irreg/gen_pl")
end
if args.want_sc1 then
track("want-sc1")
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-и$") or rfind(decl, "-а$") or rfind(decl, "-я$") then
track("irreg")
track("irreg/nom_pl")
end
if rfind(decl, "-ья$") then
track("variant-ья")
all_pl_irreg()
end
if rfind(decl, "%(ишк%)$") then
track("variant-ишко")
end
if rfind(decl, "%(ищ%)$") then
track("variant-ище")
end
if args.jo_special then
track("jo-special")
end
if args.manual then
track("manual")
end
if args.explicit_gender then
track("explicit-gender")
track("explicit-gender/" .. args.explicit_gender)
end
for _, case in ipairs(overridable_cases) do
if args[case .. n] and not args.manual then
track("override")
track("override/" .. case .. n)
track("irreg")
track("irreg/" .. case .. n)
-- questionable use: track_prefix("irreg/" .. case .. "/")
-- questionable use: track_prefix("irreg/" .. case .. n .. "/")
end
if islast and args[case] and not args.manual then
track("override")
track("override/" .. case)
track("irreg")
track("irreg/" .. case)
-- questionable use: track_prefix("irreg/" .. case .. "/")
end
if args[case .. "_tail"] then
track("casenum-tail")
track("casenum-tail/" .. case)
end
if args[case .. "_tailall"] then
track("casenum-tailall")
track("casenum-tailall/" .. case)
end
end
end
local gender_to_full = {m="ပုလ္လိၚ်", f="ဣတ္တိလိၚ်", n="နပုလ္လိၚ်"}
local gender_to_short = {m="masc", f="fem", n="neut"}
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the plural part of speech.
local function insert_category(categories, cat, pos, atbeg)
if enable_categories then
-- local fullcat = "Russian " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(categories, 1, fullcat)
else
table.insert(categories, fullcat)
end
end
end
-- Insert categories into ARGS.CATEGORIES corresponding to the specified
-- stress and declension classes and to the form of the stem (e.g. velar,
-- sibilant, etc.). Also initialize values used to compute the declension
-- heading that describes similar information. N is the number of the
-- word being processed; ISLAST is true if this is the last word.
local function categorize_and_init_heading(stress, decl, args, n, islast)
local function cat_to_list(cat)
if not cat then
return {}
elseif type(cat) == "string" then
return {cat}
else
assert(type(cat) == "table")
return cat
end
end
-- Insert category CAT into the list of categories in ARGS.
-- CAT may be nil, a single string or a list of strings. We call
-- insert_category() on each string. The strings will have "Russian "
-- prepended and "~" replaced with the plural part of speech.
local function insert_cat(cat)
for _, c in ipairs(cat_to_list(cat)) do
insert_category(args.categories, c, args.pos)
end
end
-- "Resolve" the category spec CATSPEC into the sort of category spec
-- accepted by insert_cat(), i.e. nil, a single string or a list of
-- strings. CATSPEC may be any of these or a function, which takes one
-- argument (SUFFIX) and returns another CATSPEC.
local function resolve_cat(catspec, suffix)
if type(catspec) == "function" then
return resolve_cat(catspec(suffix), suffix)
else
return catspec
end
end
-- Check whether an override for nom_sg or nom_pl still contains the
-- normal suffix (which should already have accents removed) in at least
-- one of its entries. If no override then of course we return true.
local function override_matches_suffix(args, case, n, suffix)
assert(suffix == com.remove_accents(suffix))
-- NOTE: It might not be completely correct to pass in args.forms
-- here when n == ""; this is different behavior from
-- handle_overall_forms_and_overrides(). But args.forms is only used
-- to retrieve the dat_sg for handling loc/par, and we're never
-- called with loc or par as the value of CASE, so it doesn't matter.
-- We add an assert to make sure of this.
assert(case ~= "loc" and case ~= "par")
local override = canonicalize_override(args, case, args.forms, n)
if not override then
return true
end
for _, x in ipairs(override) do
local ru, tr = x[1], x[2]
local entry, notes = m_table_tools.separate_notes(ru)
entry = com.remove_accents(m_links.remove_links(entry))
if rlfind(entry, suffix .. "$") then
return true
end
end
return false
end
if args.manual then
return
end
local h = args.heading_info
assert(decl)
local decl_cats = args.old and declensions_old_cat or declensions_cat
local sgdecl, pldecl
local is_slash_decl = rfind(decl, "/")
if is_slash_decl then
local indiv_decls = rsplit(decl, "/")
sgdecl, pldecl = indiv_decls[1], indiv_decls[2]
else
sgdecl, pldecl = decl, decl
end
local sgdc = decl_cats[sgdecl]
local pldc = decl_cats[pldecl]
assert(sgdc)
assert(pldc)
local sghint_types = com.get_stem_trailing_letter_type(
args.stem .. (sgdc.stem_suffix or ""))
-- insert English version of Zaliznyak stem type
if sgdc.decl == "indeclinable" then
insert_cat("indeclinable ~")
insert_if_not(h.stemetc, "indecl")
else
local stem_type =
sgdc.decl == "3rd" and "3rd-declension" or
m_table.contains(sghint_types, "velar") and "velar-stem" or
m_table.contains(sghint_types, "sibilant") and "sibilant-stem" or
m_table.contains(sghint_types, "c") and "ц-stem" or
m_table.contains(sghint_types, "i") and "i-stem" or
m_table.contains(sghint_types, "vowel") and "vowel-stem" or
m_table.contains(sghint_types, "soft-cons") and "vowel-stem" or
m_table.contains(sghint_types, "palatal") and "vowel-stem" or
sgdc.hard == "soft" and "soft-stem" or
"hard-stem"
local short_stem_type = stem_type == "3rd-declension" and "3rd-decl" or stem_type
if sgdc.adj then
-- Don't include gender for pluralia tantum because it's mostly
-- indeterminate (certainly when specified using a plural lemma,
-- which will be usually; technically it's partly or completely
-- determinate in certain old-style adjectives that distinguish
-- masculine from feminine/neuter, but this is too rare a case
-- to worry about)
local gendertext = args.thisn == "p" and "plural-only" or gender_to_full[sgdc.g]
insert_if_not(h.adjectival, "yes")
if args.thisn ~= "p" then
insert_if_not(h.gender, gender_to_short[sgdc.g])
end
if sgdc.possadj then
insert_cat(sgdc.decl .. " possessive " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, sgdc.decl .. " poss")
insert_if_not(h.stress, stress)
elseif stem_type == "soft-stem" or stem_type == "vowel-stem" then
insert_cat(stem_type .. " " .. gendertext .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
else
insert_cat(stem_type .. " " .. gendertext .. " accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " adjectival ~")
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
else
-- NOTE: There are 8 Zaliznyak-style stem types and 3 genders, but
-- we don't create a category for masculine-form 3rd-declension
-- nouns (there is such a noun, путь, but it mostly behaves
-- like a feminine noun), so there are 23.
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form ~")
-- NOTE: Here we are creating categories for the combination of
-- stem, gender and accent. There are 10 accent patterns and 23
-- combinations of stem and gender, which potentially makes for
-- 10*23 = 230 such categories, which is a lot. Not all such
-- categories should actually exist; there were maybe 75 former
-- declension templates, each of which was essentially categorized
-- by the same three variables, but some of which dealt with
-- ancillary issues like irregular plurals; this amounts to 67
-- actual stem/gender/accent categories, although there are more
-- of them in Zaliznyak (FIXME, how many? See generate_cats.py).
insert_cat(stem_type .. " " .. gender_to_full[sgdc.g] .. "-form accent-" .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")) .. " ~")
insert_if_not(h.adjectival, "no")
insert_if_not(h.gender, gender_to_short[sgdc.g])
insert_if_not(h.stemetc, short_stem_type)
insert_if_not(h.stress, stress)
end
insert_cat("~ with accent pattern " .. (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
local sgsuffix = args.suffixes.nom_sg
if sgsuffix then
assert(#sgsuffix == 1) -- If this ever fails, then implement a loop
sgsuffix = com.remove_accents(sgsuffix[1])
-- If we are plural only or if nom_sg is overridden and has
-- an unusual suffix, then don't create category for sg suffix
if args.thisn == "p" or not override_matches_suffix(args, "nom_sg", n, sgsuffix) or islast and not override_matches_suffix(args, "nom_sg", "", sgsuffix) then
sgsuffix = nil
end
end
local plsuffix = args.suffixes.nom_pl
if plsuffix then
assert(#plsuffix == 1) -- If this ever fails, then implement a loop
plsuffix = com.remove_accents(plsuffix[1])
-- If we are a singulare tantum or if nom_pl is overridden and has
-- an unusual suffix, then don't create category for pl suffix
if args.thisn == "s" or not override_matches_suffix(args, "nom_pl", n, plsuffix) or islast and not override_matches_suffix(args, "nom_pl", "", plsuffix) then
plsuffix = nil
end
end
sgsuffix = sgsuffix and rsub(sgsuffix, "ъ$", "")
plsuffix = plsuffix and rsub(plsuffix, "ъ$", "")
local sgcat = sgsuffix and (resolve_cat(sgdc.singular, sgsuffix) or "ending in " .. (sgsuffix == "" and "a consonant" or (sgdc.suffix and "suffix " or "") .. "-" .. sgsuffix))
local plcat = plsuffix and (resolve_cat(pldc.plural, plsuffix) or "plural -" .. plsuffix)
if sgcat and sgdc.gensg then
for _, cat in ipairs(cat_to_list(sgcat)) do
insert_cat("~ " .. cat)
end
end
if sgcat and plcat and (sgdc.suffix or sgdc.alt_nom_pl or sgdc.irregpl or
is_slash_decl and plsuffix == "-ья") then
for _, scat in ipairs(cat_to_list(sgcat)) do
for _, pcat in ipairs(cat_to_list(plcat)) do
-- insert_cat("~ " .. scat .. " with " .. pcat)
end
end
end
if args.pl ~= args.stem then
-- insert_cat("~ with irregular plural stem")
end
if args.reducible and not sgdc.ignore_reduce then
-- insert_cat("~ with reducible stem")
if args.soft_n then
-- insert_cat("~ with soft final н in reduced stem")
end
insert_if_not(h.reducible, "yes")
else
insert_if_not(h.reducible, "no")
end
if args.alt_gen_pl then
-- insert_cat("~ with alternative genitive plural")
end
if sgdc.adj then
-- insert_cat("adjectival ~")
end
end
local function compute_heading(args)
local headings = {}
local h = args.heading_info
table.insert(headings, args.a == "a" and "anim" or args.a == "i" and
"inan" or "bian")
table.insert(headings, args.nonumber and "uncountable" or
args.n == "s" and "sg-only" or args.n == "p" and "pl-only" or nil)
if #h.gender > 0 then
table.insert(headings, table.concat(h.gender, "/") .. "-form")
end
if #h.stemetc > 0 then
table.insert(headings, table.concat(h.stemetc, "/"))
end
if #h.stress > 0 then
local stresses = {}
for _, stress in ipairs(h.stress) do
table.insert(stresses, (stress:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
table.insert(headings, "accent-" .. table.concat(stresses, "/"))
end
local function handle_bool(boolvals, text, into)
into = into or headings
if m_table.contains(boolvals, "yes") and m_table.contains(boolvals, "no") then
table.insert(into, "[" .. text .. "]")
elseif m_table.contains(boolvals, "yes") then
table.insert(into, text)
end
end
handle_bool(h.adjectival, "adj")
handle_bool(h.reducible, "reduc")
return headings
end
local function compute_overall_heading_categories_and_genders(args)
local hinfo = args.per_word_heading_info
local index = 0
-- First try for non-adjectival, non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") and not m_table.contains(hinfo[i].adjectival, "yes") then
index = i
break
end
end
if index == 0 then
-- Then just non-indeclinable
for i=1,#hinfo do
if not m_table.contains(hinfo[i].stemetc, "indecl") then
index = i
break
end
end
end
-- Finally, do anything
if index == 0 then
index = 1
end
-- Compute final heading
local headings = args.per_word_headings[index]
local categories = args.per_word_categories[index]
if args.any_irreg then
table.insert(headings, "irreg")
-- insert_category(categories, "irregular ~", args.pos)
end
for _, case in ipairs(overridable_cases) do
local is_pl = rfind(case, "_pl")
if args.n == "s" and is_pl or args.n == "p" and not is_pl then
-- Don't create singular categories when plural-only or vice-versa
elseif overridable_only_cases_set[case] then
if args.any_overridden[case] then
-- insert_category(categories, "~ with " .. english_case_description(case), args.pos)
end
elseif args.any_irreg_case[case] then
-- insert_category(categories, "~ with irregular " .. english_case_description(case), args.pos)
end
end
local heading = args.manual and "" or "(<span style=\"font-size: smaller;\">[[Appendix:နာမ်ရုဿျှာဂမၠိုၚ်#Declension tables|" .. table.concat(headings, " ") .. "]]</span>)"
args.heading = heading
args.categories = categories
args.genders = args.per_word_genders[index]
end
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Used by do_generate_forms().
local function arg1_is_stress(arg1)
if not arg1 then return false end
for _, arg in ipairs(rsplit(arg1, ",")) do
if not rfind(arg, "^[a-f]'?'?$") then
return false
end
end
return true
end
-- Used by do_generate_forms(), handling a word joiner argument
-- of the form 'join:JOINER'.
local function extract_word_joiner(spec)
word_joiner = rmatch(spec, "^join:(.*)$")
assert(word_joiner)
return com.split_russian_tr(word_joiner, "dopair")
end
local function determine_headword_gender(args, sgdc, gender)
-- If gender unspecified, use normal gender of declension, except when
-- adjectival nouns that are pluralia tantum, where the gender is
-- mostly indeterminate (FIXME, not completely with old-style declensions
-- but we don't handle that currently).
if not gender then
if sgdc.adj and args.thisn == "p" then
gender = nil
else
gender = sgdc.g
end
end
-- Determine headword genders
gender = gender and gender ~= "none" and gender .. "-" or ""
local plsuffix = args.n == "p" and "-p" or ""
local hgens
if args.a == "a" then
hgens = {gender .. "an" .. plsuffix}
elseif args.a == "i" then
hgens = {gender .. "in" .. plsuffix}
elseif args.a == "ai" then
hgens = {gender .. "an" .. plsuffix, gender .. "in" .. plsuffix}
else
hgens = {gender .. "in" .. plsuffix, gender .. "an" .. plsuffix}
end
-- Insert into list of genders
for _, hgen in ipairs(hgens) do
insert_if_not(args.genders, hgen)
end
end
function export.do_generate_forms(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SETS and JOINER, where ARG_SETS
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Gather arguments into a list of ARG_SET objects, containing (potentially)
-- elements 1, 2, 3, 4, corresponding to accent pattern, stem, declension
-- type, pl stem and coming from consecutive numbered parameters. Sets of
-- declension parameters are separated by the word "or".
local arg_sets = {}
-- Find maximum-numbered arg, allowing for holes
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Now gather the arguments.
local offset = 0
local arg_set = {}
for i=1,(max_arg + 1) do
local end_arg_set = false
local end_word = false -- FIXME, is this correct?
local word_joiner
if i == max_arg + 1 then
end_arg_set = true
end_word = true
word_joiner = {""}
elseif args[i] == "_" then
end_arg_set = true
end_word = true
word_joiner = {" "}
elseif args[i] == "-" then
end_arg_set = true
end_word = true
word_joiner = {"-"}
elseif args[i] and rfind(args[i], "^join:") then
end_arg_set = true
end_word = true
word_joiner = extract_word_joiner(args[i])
elseif args[i] == "or" then
end_arg_set = true
end
if end_arg_set then
table.insert(arg_sets, arg_set)
arg_set = {}
offset = i
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
else
-- If the first argument isn't stress, that means all arguments
-- have been shifted to the left one. We want to shift them
-- back to the right one, so we change the offset so that we
-- get the same effect of skipping a slot in the arg set.
if i - offset == 1 and not arg1_is_stress(args[i]) then
offset = offset - 1
end
if i - offset > 4 then
error("Too many arguments for argument set: arg " .. i .. " = " .. (args[i] or "(blank)"))
end
arg_set[i - offset] = args[i]
end
end
return generate_forms_1(args, per_word_info)
end
function export.do_generate_forms_multi(args, old)
old = old or args.old
args.old = old
args.pos = args.pos or "နာမ်"
-- This is a list with each element corresponding to a word and
-- consisting of a two-element list, ARG_SET and JOINER, where ARG_SET
-- is a list of ARG_SET objects, one per alternative stem, and JOINER
-- is a string indicating how to join the word to the next one.
local per_word_info = {}
-- Find maximum-numbered arg, allowing for holes (FIXME: Is this needed
-- here? Will there be holes?)
local max_arg = 0
for k, v in pairs(args) do
if type(k) == "number" and k > max_arg then
max_arg = k
end
end
-- Gather arguments into a list of ARG_SET objects, containing
-- (potentially) elements 1, 2, 3, corresponding to accent pattern,
-- lemma+declension spec, pl stem, exactly as with do_generate_forms()
-- and {{ru-noun-table}} except that the values come from a single argument
-- of the form ACCENTPATTERN:LEMMADECL:PL where all but LEMMADECL may (and
-- probably will be) omitted and LEMMADECL may be of the following forms:
-- LEMMA (for a noun with empty decl spec),
-- LEMMADECL (for a noun with non-empty decl spec beginning with a
-- *, left paren or semicolon),
-- LEMMA^DECL (for a noun with non-empty decl spec),
-- LEMMA$ (for an indeclinable word)
-- LEMMA+ (for an adjective with auto-detected decl class)
-- LEMMA+DECL (for an adjective with explicit decl class)
-- Sets of parameters for the same word are separated by the word "or".
local arg_sets = {}
local continue_arg_sets = true
for i=1,(max_arg + 1) do
local end_word = false
local word_joiner
local process_arg = false
if i == max_arg + 1 then
end_word = true
word_joiner = {""}
elseif args[i] == "-" then
end_word = true
word_joiner = {"-"}
continue_arg_sets = true
elseif rfind(args[i], "^join:") then
end_word = true
word_joiner = extract_word_joiner(args[i])
continue_arg_sets = true
elseif args[i] == "or" then
continue_arg_sets = true
else
if continue_arg_sets then
continue_arg_sets = false
else
end_word = true
word_joiner = {" "}
end
process_arg = true
end
if end_word then
table.insert(per_word_info, {arg_sets, word_joiner})
arg_sets = {}
end
if process_arg then
local vals = rsplit(args[i], ":")
if #vals > 3 then
error("Can't specify more than 3 colon-separated params of param set: " .. args[i])
end
local arg_set = {}
if arg1_is_stress(vals[1]) then
arg_set[1] = vals[1]
arg_set[2] = vals[2]
arg_set[4] = vals[3]
else
arg_set[2] = vals[1]
arg_set[4] = vals[2]
end
-- recognize indeclinable
local indecl_stem = rmatch(arg_set[2], "^(.-)%$$")
if indecl_stem then
arg_set[2] = indecl_stem
arg_set[3] = "$"
else
-- recognize adjective
local adj_stem, adj_type = rmatch(arg_set[2], "^(.*)(%+.*)$")
if adj_stem then
arg_set[2] = adj_stem
arg_set[3] = adj_type
else
-- recognize noun with ^
local noun_stem, noun_type = rmatch(arg_set[2], "^(.*)%^(.*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- recognize noun without ^ but with decl spec
noun_stem, noun_type = rmatch(arg_set[2], "^(..-)([;*(].*)$")
if noun_stem then
arg_set[2] = noun_stem
arg_set[3] = noun_type
else
-- noun without ^ or decl spec; nothing to do
end
end
end
end
table.insert(arg_sets, arg_set)
end
end
return generate_forms_1(args, per_word_info)
end
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence.
-- Implementation of do_generate_forms() and do_generate_forms_multi(),
-- which have equivalent functionality but different calling sequence,
-- as well as show_z() for template {{ru-decl-noun-z}}, which has a
-- subset of the functionality of the other two.
generate_forms_1 = function(args, per_word_info)
local orig_args
if test_new_ru_noun_module then
orig_args = mw.clone(args)
end
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local old = args.old
local function verify_animacy_value(val)
if not val then return nil end
if val == "a" or val == "an" or val == "anim" then
return "a"
elseif val == "i" or val == "in" or val == "inan" then
return "i"
elseif val == "b" or val == "bi" or val == "both" or val == "ai" then
return "ai"
elseif val == "ia" then
return "ia"
end
error("Animacy value " .. val .. " should be empty or a/an/anim (animate), i/in/inan (inanimate), b/bi/both/ai (bianimate, listing animate first), or ia (bianimate, listing inanimate first)")
return nil
end
local function verify_number_value(val, allow_none)
if not val then return nil end
local short = usub(val, 1, 1)
if short == "s" or short == "p" or short == "b" or (allow_none and short == "n" or false) then
return short
end
if allow_none then
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), 'b' (both) or 'n' (none)")
else
error("Number value " .. val .. " should be empty or start with 's' (singular), 'p' (plural), or 'b' (both)")
end
return nil
end
-- Verify and canonicalize animacy, number, prefix, suffix
assert(#per_word_info >= 1)
for i=1,#per_word_info do
args["a" .. i] = verify_animacy_value(args["a" .. i])
args["n" .. i] = verify_number_value(args["n" .. i])
args["prefix" .. i] = com.split_russian_tr(args["prefix" .. i] or "", "dopair")
args["suffix" .. i] = com.split_russian_tr(args["suffix" .. i] or "", "dopair")
end
args.a = verify_animacy_value(args.a) or "i"
-- args.ndef, if set, is the default value for args.n; if unset, it defaults
-- to "both". It is set to "singular" in ru-proper noun+. We store the value
-- of args.n in args.orign before defaulting to args.ndef because we may
-- change it to plural-only later on if it was unspecified (this happens if
-- an individual word's lemma is plural), and to determine whether it was
-- unspecified, we need the original value before defaulting.
args.n = verify_number_value(args.n, "allow none")
-- treat n=none like n=sg but set a flag so "singular" isn't displayed
if args.n == "n" then
args.n = "s"
args.nonumber = true
end
args.ndef = verify_number_value(args.ndef)
args.orign = args.n
args.n = args.n or args.ndef
args.prefix = com.split_russian_tr(args.prefix or "", "dopair")
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
-- Attach overall prefix to first per-word prefix, similarly for suffix
args.prefix1 = com.concat_paired_russian_tr(args.prefix, args.prefix1)
args["suffix" .. #per_word_info] = com.concat_paired_russian_tr(
args["suffix" .. #per_word_info], args.suffix)
-- Initialize non-word-specific arguments.
--
-- The following is a list of WORD_INFO items, one per word, each of
-- which is a two element list of WORD_FORMS (a table listing the forms for
-- each case) and JOINER (a string, indicating how to join the word with
-- the next one).
args.per_word_info = {}
-- List of HEADING_INFO items, one per word, containing the raw material
-- used to generate the header. Initialized from 'args.heading_info',
-- which is initialized in categorize_and_init_heading().
args.per_word_heading_info = {}
-- List of CATEGORIES items, one per word, containing the categories
-- used to initialize the page categories. Initialized from
-- 'args.categories', which is initialized in categorize_and_init_heading().
args.per_word_categories = {}
-- List of HEADINGS items, one per word, containing the actual words that
-- go into the header if we were to use that word to construct the header.
-- Comes from compute_heading(). We use this to generate the actual header
-- string, which goes into 'args.heading' at the end (done in
-- compute_overall_heading_categories_and_genders()).
args.per_word_headings = {}
-- List of GENDERS items, one per word, containing the headword genders
-- for each word (where "headword gender" is in the format used in
-- headwords and actually includes animacy and number as well, e.g.
-- 'm-in' or 'f-an-p'). We end up selecting one such item and putting
-- it into 'args.genders' at the end
-- (in compute_overall_heading_categories_and_genders()).
args.per_word_genders = {}
args.any_overridden = {}
args.any_non_nil = {}
args.any_irreg = false
args.any_irreg_case = {}
local function insert_cat(cat)
insert_category(args.categories, cat, args.pos)
end
args.internal_notes = {}
local decl_sufs = old and declensions_old or declensions
local decl_cats = old and declensions_old_cat or declensions_cat
local intable = old and internal_notes_table_old or internal_notes_table
-- Default lemma defaults to previous lemma, first one to page name.
-- FIXME: With multiple words, we should probably split the page name
-- on spaces and default each word in turn
local default_lemma
local all_stresses_seen
-- Made into a function to avoid having to indent a lot of code.
-- Process a single arg set of a single word. This inserts the forms
-- for the word into args.forms and sets categories and tracking pages.
local function do_arg_set(arg_set, n, islast)
local stress_arg = arg_set[1]
local decl = arg_set[3] or ""
local pl, pltr
if arg_set[4] then
pl, pltr = com.split_russian_tr(arg_set[4])
end
-- Extract special markers from declension class.
if decl == "manual" then
decl = "$"
args.manual = true
if #per_word_info > 1 or #per_word_info[1][1] > 1 then
error("Can't specify multiple words or argument sets when manual")
end
if pl then
error("Can't specify optional stem parameters when manual")
end
end
decl, args.jo_special = rsubb(decl, "([^/%a])ё$", "%1")
if not args.jo_special then
decl, args.jo_special = rsubb(decl, "([^/%a])ё([^/%a])", "%1%2")
end
decl, args.want_sc1 = rsubb(decl, "%(1%)", "")
decl, args.alt_gen_pl = rsubb(decl, "%(2%)", "")
decl, args.reducible = rsubb(decl, "%*", "")
decl, args.soft_n = rsubb(decl, "%(нь%)", "")
decl = rsub(decl, ";", "")
-- Get the lemma.
local lemma = args.manual and "-" or arg_set[2] or default_lemma
if not lemma then
error("Lemma in first argument set must be specified")
end
default_lemma = lemma
local lemmatr
lemma, lemmatr = com.split_russian_tr(lemma)
-- If we're conjugating a suffix, insert a pseudoconsonant at the beginning
-- of all forms, so they get conjugated as if ending in a consonant.
-- We remove the pseudoconsonant later.
local is_suffix = lemma ~= "-" and rfind(lemma, "^%-")
args.any_suffix = args.any_suffix or is_suffix
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or is_suffix and PSEUDOCONS
if asif_prefix then
lemma = rsub(lemma, "^%-", "-" .. asif_prefix)
if lemmatr then
lemmatr = rsub(lemmatr, "^%-", "-" .. com.translit(asif_prefix))
end
end
args.thisa = args["a" .. n] or args.a
args.thisn = args["n" .. n] or args.n
-- Check for explicit allow-unaccented indication.
local allow_unaccented
lemma, allow_unaccented = rsubb(lemma, "^%*", "")
args.allow_unaccented = args.allow_unaccented or allow_unaccented
if args.allow_unaccented then
track("allow-unaccented")
end
args.orig_lemma = lemma
lemma = m_links.remove_links(lemma)
args.lemma_no_links = lemma
args.lemmatr = lemmatr
if args.lemma then
-- Explicit lemma given.
args.explicit_lemma, args.explicit_lemmatr = com.split_russian_tr(args.lemma)
end
-- Treat suffixes without an accent, and suffixes with an accent on the
-- initial hyphen, as if they were preceded with a *, which overrides
-- all the logic that normally (a) normalizes the accent, and (b)
-- complains about multisyllabic words without an accent. Don't do this
-- if lemma is just -, which is used specially in manual declension
-- tables (e.g. сто, три).
if lemma ~= "-" and (rfind(lemma, "^%-" .. AC) or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
-- Convert lemma and decl arg into stem and canonicalized decl.
-- This will autodetect the declension from the lemma if an explicit
-- decl isn't given.
local stem, tr, gender, was_accented, was_plural, was_autodetected
if rfind(decl, "^%+") then
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
detect_adj_type(lemma, lemmatr, decl, old)
else
stem, tr, decl, gender, was_accented, was_plural, was_autodetected =
determine_decl(lemma, lemmatr, decl, args)
end
if was_plural then
args.n = args.orign or "p"
args.thisn = args["n" .. n] or args.n
elseif decl ~= "$" then
args.thisn = args.thisn or "b"
end
args.explicit_gender = gender
-- If allow-unaccented not given, maybe check for missing accents.
if not args.allow_unaccented and not stress_arg and was_autodetected and com.needs_accents(lemma) then
-- If user gave the full word and expects us to determine the
-- declension and stress, the word should have an accent on the
-- stem or ending. We have a separate check farther below for
-- an accent on a multisyllabic stem, after stripping off any
-- ending; but this way we get an error if the user e.g. writes
-- "гора" without an accent rather than assuming it's stem
-- stressed, as would otherwise happen.
error("Lemma must have an accent in it: " .. lemma)
end
-- If stress not given, auto-determine; else validate/canonicalize
-- stress arg, override in certain cases and convert to list.
if not stress_arg then
stress_arg = {detect_stress_pattern(stem, decl, decl_cats, args.reducible, was_plural, was_accented)}
else
stress_arg = rsplit(stress_arg, ",")
for i=1,#stress_arg do
local stress = stress_arg[i]
stress = override_stress_pattern(decl, stress)
if not stress_patterns[stress] then
error("Unrecognized accent pattern " .. stress)
end
stress_arg[i] = stress
end
end
-- parse slash decl to list
local sub_decls
if rfind(decl, "/") then
track("mixed-decl")
insert_cat("~ with mixed declension")
local indiv_decls = rsplit(decl, "/")
-- Should have been caught in canonicalize_decl()
assert(#indiv_decls == 2)
sub_decls = {{indiv_decls[1], "sg"}, {indiv_decls[2], "pl"}}
else
sub_decls = {{decl}}
end
-- Get singular declension and corresponding category.
local sgdecl = sub_decls[1][1]
local sgdc = decl_cats[sgdecl]
assert(sgdc)
-- Compute headword gender(s). We base it off the singular declension
-- if we have a slash declension -- it's the best we can do.
determine_headword_gender(args, sgdc, gender)
local original_stem, original_tr = stem, tr
local original_pl, original_pltr = pl, pltr
-- Loop over accent patterns in case more than one given.
for _, stress in ipairs(stress_arg) do
args.suffixes = {}
stem, tr = original_stem, original_tr
local bare, baretr
local stem_for_bare, tr_for_bare
pl, pltr = original_pl, original_pltr
insert_if_not(all_stresses_seen, stress)
local stem_was_unstressed = com.is_unstressed(stem)
-- If special case ;ё was given and stem is unstressed,
-- add ё to the stem now; but don't let this interfere with
-- restressing, to handle cases like железа́ with gen pl желёз
-- but nom pl же́лезы.
if stem_was_unstressed and args.jo_special then
-- Beware, Cyrillic еЕ in first rsub, Latin eE in second
local new_stem = rsub(stem, "([еЕ])([^еЕ]*)$",
function(e, rest)
return (e == "Е" and "Ё" or "ё") .. rest
end
)
if stem == new_stem then
error("No е in stem to replace with ё")
end
stem = new_stem
if tr then
local subbed
-- e after j -> o, e not after j -> jo; don't just convert e -> jo
-- and then map jjo -> jo because we want to preserve double j
tr, subbed = rsubb(tr, "([jJ])([eE])([^eE]*)$",
function(j, e, rest)
return j .. (e == "E" and "O" or "o") .. AC .. rest
end
)
if not subbed then
tr = rsub(tr, "([eE])([^eE]*)$",
function(e, rest)
return (e == "E" and "Jo" or "jo") .. AC .. rest
end
)
end
tr = com.j_correction(tr)
end
-- This is used to handle железа́ with gen pl желёз and nom pl
-- же́лезы. We have two stressed stems, one for the gen pl and
-- one for the remaining pl cases, and the variable 'stem' can
-- handle only one, so we put the second (gen pl) stem in
-- stem_for_bare, which goes into the value of 'bare' (used
-- only for gen pl here).
stem_for_bare, tr_for_bare = stem, tr
end
-- Maybe add stress to the stem, depending on whether the
-- stem was unstressed and the stress pattern. Stem pattern f
-- and variants call for initial stress (голова́ -> го́ловы);
-- stem pattern d and variants call for stem-final stress
-- (сапожо́к -> сапо́жки). Stem patterns b and b' apparently
-- call for stem-final stress as well but it's unlikely to
-- make much of a difference (pattern b' only occurs in 3rd-decl
-- feminines, which should already have stress in the stem,
-- and the only place pattern b gets stem stress is in bare
-- forms, i.e. nom sg and/or gen pl depending on the decl type,
-- and nom sg stress should already be in the lemma while
-- gen pl stress is handled by a different ending-stressing
-- mechanism in attach_unstressed(); however, the user is
-- free to leave a masc or 3rd-decl fem lemma completely
-- unstressed with pattern b, and then the stem-final stress
-- *will* make a difference).
local function restress_stem(stem, tr, stress, stem_unstressed)
-- If the user has indicated they purposely are leaving the
-- word unstressed by putting a * at the beginning of the main
-- stem, leave it unstressed. This might indicate lack of
-- knowledge of the stress or a truly unaccented word
-- (e.g. an unaccented suffix).
if args.allow_unaccented then
return stem, tr
end
if tr and com.is_unstressed(stem) ~= com.is_unstressed(tr) then
error("Stem " .. stem .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(stem) then
stem, tr = com.make_ending_stressed(stem, tr)
-- For those patterns that are ending-stressed in the singular
-- nominative (and hence are likely to be expressed without an
-- accent on the stem) it's safe to put a particular accent on
-- the stem depending on the stress type. Otherwise, give an
-- error if no accent.
elseif stem_unstressed then
if rfind(stress, "^f") then
stem, tr = com.make_beginning_stressed(stem, tr)
elseif (rfind(stress, "^[bd]") or
args.thisn == "p" and ending_stressed_pl_patterns[stress]) then
stem, tr = com.make_ending_stressed(stem, tr)
elseif com.needs_accents(stem) then
error("Stem " .. stem .. " requires an accent")
end
end
return stem, tr
end
stem, tr = restress_stem(stem, tr, stress, stem_was_unstressed)
-- Leave pl unaccented if user wants this; see restress_stem().
if pl and not args.allow_unaccented then
if pltr and com.is_unstressed(pl) ~= com.is_unstressed(pltr) then
error("Plural stem " .. pl .. " and translit " .. pltr .. " must have same accent pattern")
end
if com.is_monosyllabic(pl) then
pl, pltr = com.make_ending_stressed(pl, pltr)
end
-- I think this is safe.
if com.needs_accents(pl) then
if ending_stressed_pl_patterns[stress] then
pl, pltr = com.make_ending_stressed(pl, pltr)
elseif not args.allow_unaccented then
error("Plural stem " .. pl .. " requires an accent")
end
end
end
local resolved_bare, resolved_baretr
-- Handle (de)reducibles
-- FIXME! We are dereducing based on the singular declension.
-- In a slash declension things can get weird and we don't
-- handle that. We are also computing the bare value from the
-- singular stem, and again things can get weird with a plural
-- stem. Note that we don't compute a bare value unless we have
-- to (either (de)reducible or stress pattern f/f'/f'' combined
-- with ё special case); the remaining times we generate the bare
-- value directly from the plural stem.
if args.reducible and not sgdc.ignore_reduce then
-- Zaliznyak treats all nouns in -ье and -ья as being
-- reducible. We handle this automatically and don't require
-- the user to specify this, but ignore it if so for
-- compatibility.
if is_reducible(sgdc) then
-- If we derived the stem from a nom pl form, then
-- it's already reduced, and we need to dereduce it to
-- get a bare form; otherwise the stem comes from the
-- nom sg and we need to reduce it to get the real stem.
if was_plural then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
resolved_bare, resolved_baretr = stem, tr
stem, tr = export.reduce_nom_sg_stem(stem, tr,
sgdecl, args.soft_n, "error")
-- Stem will be unstressed if stress was on elided
-- vowel; restress stem the way we did above. (This is
-- needed in at least one word, сапожо́к 3*d(2), with
-- plural stem probably сапо́жк- and gen pl probably
-- сапо́жек.)
stem, tr = restress_stem(stem, tr, stress,
com.is_unstressed(stem))
if stress ~= "a" and stress ~= "b" and args.alt_gen_pl and not pl then
-- Nouns like рожо́к, глазо́к of type 3*d(2) have
-- gen pl's ро́жек, гла́зок; to handle this,
-- dereduce the reduced stem and store in a
-- special place.
args.gen_pl_bare, args.gen_pl_baretr =
export.dereduce_nom_sg_stem(stem, tr,
sgdc, stress, old, "error")
end
end
elseif is_dereducible(sgdc) then
resolved_bare, resolved_baretr =
export.dereduce_nom_sg_stem(stem, tr, sgdc,
stress, old, "error")
else
error("Declension class " .. sgdecl .. " not (de)reducible")
end
elseif stem_for_bare and stem ~= stem_for_bare then
resolved_bare, resolved_baretr =
add_bare_suffix(stem_for_bare, tr_for_bare, old, sgdc, false)
end
-- Leave unaccented if user wants this; see restress_stem().
-- FIXME, we no longer allow the user to specify the bare value
-- so it's unclear if this is needed any more.
if resolved_bare and not args.allow_unaccented then
if resolved_baretr and com.is_unstressed(resolved_bare) ~= com.is_unstressed(resolved_baretr) then
error("Resolved bare stem " .. resolved_bare .. " and translit " .. resolved_baretr .. " must have same accent pattern")
end
if com.is_monosyllabic(resolved_bare) then
resolved_bare, resolved_baretr =
com.make_ending_stressed(resolved_bare, resolved_baretr)
else
if com.needs_accents(resolved_bare) then
error("Resolved bare stem " .. resolved_bare .. " requires an accent")
end
end
end
args.stem, args.stemtr = stem, tr
args.bare, args.baretr = resolved_bare, resolved_baretr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, tr)
if pl then
args.pl, args.pltr = pl, pltr
else
args.pl, args.pltr = stem, tr
end
args.upl, args.upltr = com.make_unstressed_once(args.pl, args.pltr)
-- Special hack for любо́вь and other reducible 3rd-fem nouns,
-- which have the full stem in the ins sg
args.ins_sg_stem = sgdecl == "ь-f" and args.reducible and resolved_bare
args.ins_sg_tr = sgdecl == "ь-f" and args.reducible and resolved_baretr
-- Loop over declension classes (we may have two of them, one for
-- singular and one for plural, in the case of a mixed declension
-- class of the form SGDECL/PLDECL).
for _,decl_spec in ipairs(sub_decls) do
local orig_decl = decl_spec[1]
local number = decl_spec[2]
local real_decl =
determine_stress_variant(orig_decl, stress)
real_decl = determine_stem_variant(real_decl,
number == "pl" and args.pl or args.stem)
-- sanity checking; errors should have been caught in
-- canonicalize_decl()
assert(decl_cats[real_decl], "real_decl " .. real_decl .. " nonexistent")
assert(decl_sufs[real_decl], "real_decl " .. real_decl .. " nonexistent")
tracking_code(stress, orig_decl, real_decl, args, n, islast)
do_stress_pattern(stress, args, real_decl, number, n, islast)
-- handle internal notes
local internal_note = intable[real_decl]
if internal_note then
insert_if_not(args.internal_notes, internal_note)
end
end
categorize_and_init_heading(stress, decl, args, n, islast)
end
end
local n = 0
for _, word_info in ipairs(per_word_info) do
n = n + 1
local islast = n == #per_word_info
local arg_sets, joiner = word_info[1], word_info[2]
args.forms = {}
args.heading_info = {animacy={}, number={}, gender={}, stress={},
stemetc={}, adjectival={}, reducible={}}
args.categories = {}
args.genders = {}
args.this_any_non_nil = {}
args.any_suffix = false
if #arg_sets > 1 then
track("multiple-arg-sets")
-- insert_cat("~ with multiple argument sets")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
default_lemma = pagename
all_stresses_seen = {}
-- Loop over all arg sets.
for _, arg_set in ipairs(arg_sets) do
do_arg_set(arg_set, n, islast)
end
if #all_stresses_seen > 1 then
track("multiple-accent-patterns")
-- insert_cat("~ with multiple accent patterns")
track("multiple-declensions")
-- insert_cat("~ with multiple declensions")
end
table.insert(args.per_word_heading_info, args.heading_info)
table.insert(args.per_word_categories, args.categories)
local headings = compute_heading(args)
table.insert(args.per_word_headings, headings)
table.insert(args.per_word_genders, args.genders)
handle_forms_and_overrides(args, n, islast)
if args.any_suffix then
-- If we're conjugating a suffix, remove the pseudoconsonant or asif_prefix
-- that we previously inserted at the beginning.
local asif_prefix = args["asif_prefix" .. n] or args.asif_prefix or PSEUDOCONS
local asif_prefix_tr = com.translit(asif_prefix)
for _, case in ipairs(all_cases) do
if args.forms[case] then
local newforms = {}
for _, form in ipairs(args.forms[case]) do
local formru = form[1]
local formtr = form[2]
formru = rsub(formru, "^%-" .. asif_prefix, "-")
if formtr then
formtr = rsub(formtr, "^%-" .. asif_prefix_tr, "-")
end
if formru == "-" then
-- if no ending, insert "(no suffix)".
table.insert(newforms, {"(no suffix)"})
else
table.insert(newforms, {formru, formtr})
end
end
args.forms[case] = newforms
end
end
end
table.insert(args.per_word_info, {args.forms, joiner})
end
handle_overall_forms_and_overrides(args)
compute_overall_heading_categories_and_genders(args)
for _, case in ipairs(all_cases) do
if args[case] then
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
ruentry = m_links.remove_links(ruentry)
if rfind(ulower(ruentry), latin_text_class) then
--error("Found Latin text " .. ruentry .. " in case " .. case)
track("latin-text")
track("latin-text/" .. case)
end
end
end
end
-- Test code to compare existing module to new one.
if test_new_ru_noun_module then
local m_new_ru_noun = require("Module:User:Benwing2/ru-noun")
local newargs = m_new_ru_noun.do_generate_forms(orig_args, old)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
local is_pl = rfind(case, "_pl")
if args.thisn == "s" and is_pl or args.thisn == "p" and not is_pl then
-- Don't need to check cases that won't be displayed.
elseif not m_table.deepEquals(arg, newarg) then
local monosyl_accent_diff = false
-- Differences only in monosyllabic accents. Enable if we
-- change the algorithm for these.
--if arg and newarg and #arg == 1 and #newarg == 1 then
-- local ru1, tr1 = arg[1][1], arg[1][2]
-- local ru2, tr2 = newarg[1][1], newarg[1][2]
-- if com.is_monosyllabic(ru1) and com.is_monosyllabic(ru2) then
-- ru1, tr1 = com.remove_accents(ru1, tr1)
-- ru2, tr2 = com.remove_accents(ru2, tr2)
-- if ru1 == ru2 and tr1 == tr2 then
-- monosyl_accent_diff = true
-- end
-- end
--end
if monosyl_accent_diff then
track("monosyl-accent-diff")
difdecl = true
else
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
end
if not difdecl then track("same-decl") end
end
return args
end
-- Implementation of main entry point
local function do_show(frame, old)
local args = clone_args(frame)
local args = export.do_generate_forms(args, old)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- Implementation of new entry point, esp. for multiple words
local function do_show_multi(frame)
local args = clone_args(frame)
local args = export.do_generate_forms_multi(args)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The new entry point, esp. for multiple words (but works fine for
-- single words).
function export.show_multi(frame)
return do_show_multi(frame)
end
local function get_form(forms, preserve_links, raw)
local canon_forms = {}
for _, form in ipairs(forms) do
if raw then
local ru, tr = form[1], form[2]
ru = rsub(ru, "|", "<!>")
if tr then
tr = rsub(tr, "|", "<!>")
end
insert_if_not(canon_forms, {ru, tr})
else
local ru, tr = form[1], form[2]
local ruentry, runotes = m_table_tools.separate_notes(ru)
-- Skip hypothetical forms (but include in the raw versions)
if not rfind(runotes, HYPMARKER) then
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.separate_notes(tr)
end
if not preserve_links then
ruentry = m_links.remove_links(ruentry)
end
ruentry = rsub(ruentry, "|", "<!>")
if trentry then
trentry = rsub(trentry, "|", "<!>")
end
insert_if_not(canon_forms, {ruentry, trentry})
end
end
end
return com.concat_forms(canon_forms)
end
local function case_will_be_displayed(args, case)
local ispl = rfind(case, "_pl")
local caseok = true
if args.n == "p" then
caseok = ispl
elseif args.n == "s" then
caseok = not ispl
end
for _, override_case in ipairs(overridable_only_cases) do
if case == override_case and not args.any_overridden[override_case] then
caseok = false
break
end
end
if args.a == "a" or args.a == "i" then
if rfind(case, "_[ai]n") then
caseok = false
end
else -- bianimate
-- don't include inanimate/animate variants if combined variant exists
-- (typically because inanimate/animate variants are the same);
-- FIXME: This could conceivably be different from how the display
-- code works, which just checks that the inanimate/animate variants
-- are the same when deciding whether to display them, in particular
-- if there is an override. Here we are following the algorithm of
-- handle_overall_forms_and_overrides().
if (case == "acc_sg_in" or case == "acc_sg_an") and args.acc_sg or
(case == "acc_pl_in" or case == "acc_pl_an") and args.acc_pl then
caseok = false
end
end
if not args[case] then
caseok = false
end
return caseok
end
local function concat_case_args(args, do_all, raw)
local ins_text = {}
for _, case in ipairs(do_all and all_cases or overridable_cases) do
if case_will_be_displayed(args, case) then
local forms = get_form(args[case], rfind(case, "_linked"), raw)
if forms ~= "" then
table.insert(ins_text, case .. (raw and "_raw" or "") .. "=" ..
forms)
end
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-noun-forms' to generate all noun forms.
-- This returns a single string, with | separating arguments and named
-- arguments of the form NAME=VALUE.
function export.generate_forms(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
return concat_case_args(args)
end
-- The entry point to generate multiple sets of noun forms. This is a hack
-- to speed up calling from a bot, where we often want to compare old and new
-- argument results to make sure they're the same. Each set of arguments is
-- jammed together into a single argument with individual values separated by
-- <!>; named arguments are of the form NAME<->VALUE. The return value for
-- each set of arguments is as in export.generate_forms(), and the return
-- values are concatenated with <!> separating them. NOTE: This will fail if
-- the exact sequences <!> or <-> happen to occur in values (which is unlikely,
-- esp. as we don't even use the characters <, ! or > for anything) and aren't
-- HTML-escaped.
function export.generate_multi_forms(frame)
local retvals = {}
for _, argset in ipairs(frame.args) do
local args = {}
local i = 0
local argvals = rsplit(argset, "<!>")
for _, argval in ipairs(argvals) do
local split_arg = rsplit(argval, "<%->")
if #split_arg == 1 then
i = i + 1
args[i] = ine(split_arg[1])
else
assert(#split_arg == 2)
args[split_arg[1]] = ine(split_arg[2])
end
end
args = export.do_generate_forms(args, false)
table.insert(retvals, concat_case_args(args))
end
return table.concat(retvals, "<!>")
end
-- The entry point for 'ru-noun-form' to generate a particular noun form.
function export.generate_form(frame)
local args = clone_args(frame)
if not args.form then
error("Must specify desired form using form=")
end
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
local args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
-- The entry point for generating arguments of various sorts, including
-- the case forms, gender, number and animacy.
function export.generate_args(frame)
local args = clone_args(frame)
args = export.do_generate_forms(args, false)
local retargs = {}
table.insert(retargs, concat_case_args(args, "doall"))
table.insert(retargs, concat_case_args(args, "doall", "raw"))
table.insert(retargs, "g=" .. table.concat(args.genders, ","))
-- The following is correct even with ndef because if ndef is
-- set we will set it in args.n.
table.insert(retargs, "n=" .. (args.n or "b"))
table.insert(retargs, "a=" .. (args.a or "i"))
return table.concat(retargs, "|")
end
-- The entry point for compatibility with {{ru-decl-noun-z}}.
function export.show_z(frame)
local args = clone_args(frame)
local stem = args[1]
local stress = args[2]
local specific = args[4] or ""
-- Parse gender/animacy spec
local gender, anim = rmatch(args[3], "^([mfn])-([a-z]+)")
if not gender then
error("Unrecognized gender/anim spec " .. args[3])
end
if anim ~= "an" and anim ~= "in" then anim = "both" end
args.a = anim
-- Handle specific
specific = rsub(specific, "ё", ";ё")
-- Compute decl; special case for семьянин (perhaps not necessary)
local decl = com.make_unstressed_once(stem) == "семьянин" and "#" .. specific or gender .. specific
-- Handle overrides
args.pre_sg = args.prp_sg
args.pre_pl = args.prp_pl
args.notes = args.note
if args.par then
args.par = "+"
end
if args.loc then
if args.loc == "в" then
args.loc = "в +"
elseif args.loc == "на" then
args.loc = "на +"
else
args.loc = "в +,на +"
end
end
local arg_set = {}
table.insert(arg_set, stress)
table.insert(arg_set, stem)
table.insert(arg_set, decl)
local per_word_info = {{{arg_set}, ""}}
return generate_forms_1(args, per_word_info)
end
--------------------------------------------------------------------------
-- Autodetection and lemma munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the stem and the ending. GENDER must be present with -ь and plural
-- stems, and is otherwise ignored. Return up to three values: The stem
-- (lemma minus ending), the singular lemma ending, and if the lemma was
-- plural, the plural lemma ending. If the lemma was singular, the singular
-- lemma ending will contain any user-given accents; likewise, if the
-- lemma was plural, the plural ending will contain such accents.
-- VARIANT comes from the declension spec and controls certain declension
-- variants.
local function detect_lemma_type(lemma, tr, gender, args, variant)
local base, ending = rmatch(lemma, "^(.*)([еЕ]" .. AC .. ")$") -- accented
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([еЕ])$") -- unaccented
if base then
if variant == "-ище" and not rfind(lemma, "[щЩ][еЕ]$") then
error("With declension variant -ище, lemma should end in -ще: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), variant == "-ище" and "(ищ)е-и" or "о"
end
if variant == "-ишко" then
base, ending = rmatch(lemma, "^(.*[шШ][кК])([оО])$") -- unaccented
if not base then
error("With declension variant -ишко, lemma should end in -шко: " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), "(ишк)о-и"
end
if variant == "-ин" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$") -- maybe accented
if not base then
error("With declension variant -ин, lemma should end in -ин(ъ): " .. lemma)
end
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
-- Now autodetect -ин; only animate and in -анин/-янин
base, ending = rmatch(lemma, "^(.*[аАяЯ][" .. AC .. GR .. "]?[нН])([иИ][" .. AC .. GR .. "]?[нН][ъЪ]?)$")
-- Need to check the animacy to avoid nouns like маиганин, цианин,
-- меланин, соланин, etc.
if base and args.thisa == "a" then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ёЁ]" .. AC .. "?[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*[" .. com.sib_c .. "])([оО]" .. AC .. "[нН][оО][чЧ][еЕ][кК][ъЪ]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([мМ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
--recognize plural endings
if gender == "n" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
-- Don't do this; о/-ья is too rare
-- error("Ambiguous plural lemma " .. lemma .. " in -ья, singular could be -о or -ье/-ьё; specify the singular")
return base, com.strip_tr_ending(tr, ending), "ье", ending
end
base, ending = rmatch(lemma, "^(.*)([аяАЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), rfind(ending, "[аА]") and "о" or "е", ending
end
base, ending = rmatch(lemma, "^(.*)([ыиЫИ][" .. AC .. GR .. "]?)$")
if base then
if rfind(ending, "[ыЫ]") or rfind(base, "[" .. com.sib .. com.velar .. "]$") then
return base, com.strip_tr_ending(tr, ending), "о-и", ending
else
-- FIXME, should we return a slash declension?
error("No neuter declension е-и available; use a slash declension")
end
end
end
if gender == "f" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ья", ending
end
end
-- Recognize masculines with irregular plurals, but only if the user
-- either explicitly specified that this noun is plural (n=p) or
-- specifically requested the irregular plural. This is necessary
-- because some masculine nouns have feminine endings, which look
-- like irregular plurals.
if gender == "m" then
if args.thisn == "p" or variant == "-ья" then
base, ending = rmatch(lemma, "^(.*)([ьЬ][яЯ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-ья" or "-ья"), ending
end
end
if args.thisn == "p" or args.want_sc1 then
base, ending = rmatch(lemma, "^(.*)([аА][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), (args.old and "ъ-а" or "-а"), ending
end
base, ending = rmatch(lemma, "^(.*)([яЯ][" .. AC .. GR .. "]?)$")
if base then
if rfind(base, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return base, com.strip_tr_ending(tr, ending), "й-я", ending
else
return base, com.strip_tr_ending(tr, ending), "ь-я", ending
end
end
end
end
if gender == "m" or gender == "f" then
base, ending = rmatch(lemma, "^(.*[" .. com.sib .. com.velar .. "])([иИ][" .. AC .. GR .. "]?)$")
if not base then
base, ending = rmatch(lemma, "^(.*)([ыЫ][" .. AC .. GR .. "]?)$")
end
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and (args.old and "ъ" or "") or "а", ending
end
base, ending = rmatch(lemma, "^(.*[" .. com.vowel .. "й][" .. AC .. GR .. "]?)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "й" or "я", ending
end
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), gender == "m" and "ь-m" or "я", ending
end
end
if gender == "3f" then
base, ending = rmatch(lemma, "^(.*)([иИ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), "ь-f", ending
end
end
-- end of recognize-plurals code
base, ending = rmatch(lemma, "^(.*)([ьЬ][яеёЯЕЁ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([йаяеоёъЙАЯЕОЁЪ][" .. AC .. GR .. "]?)$")
if base then
return base, com.strip_tr_ending(tr, ending), ulower(ending)
end
base, ending = rmatch(lemma, "^(.*)([ьЬ])$")
if base then
if gender == "m" or gender == "f" then
return base, com.strip_tr_ending(tr, ending), "ь-" .. gender
elseif gender == "3f" then
return base, com.strip_tr_ending(tr, ending), "ь-f"
else
error("Need to specify gender m or f with lemma in -ь: ".. lemma)
end
end
if rfind(lemma, "[ыиЫИ][" .. AC .. GR .. "]?$") then
error("If this is a plural lemma, gender must be specified: " .. lemma)
elseif rfind(lemma, "[иИіІуУыЫѣѢэЭюЮѵѴ]" .. DIA .. "?[" .. AC .. GR .. "]?$") then
error("Don't know how to decline lemma ending in this type of vowel: " .. lemma)
end
return lemma, tr, ""
end
local plural_variant_detection_map = {
[""] = {["-ья"]="-ья"},
["ъ"] = {["-ья"]="ъ-ья"},
}
local special_case_1_to_plural_variant = {
[""] = "-а",
["ъ"] = "ъ-а",
["й"] = "й-я",
["ь-m"] = "ь-я",
["о"] = "о-и",
-- these last two are here to avoid getting errors in that checks for
-- compatibility with special case 1; the basic variants of these decls
-- don't actually exist
["(ишк)о"] = "(ишк)о-и",
["(ищ)е"] = "(ищ)е-и",
}
local function map_decl(decl, fun)
if rfind(decl, "/") then
local split_decl = rsplit(decl, "/")
if #split_decl ~= 2 then
error("Mixed declensional class " .. decl
.. "needs exactly two classes, singular and plural")
end
return fun(split_decl[1]) .. "/" .. fun(split_decl[2])
else
return fun(decl)
end
end
-- Canonicalize decl class into non-accented and alias-resolved form;
-- but note that some canonical decl class names with an accent in them
-- (e.g. е́, not the same as е, whose accented version is ё; and various
-- adjective declensions).
local function canonicalize_decl(decl, old)
local function do_canon(decl)
-- remove accents, but not from е́ (for adj decls, accent matters
-- as well but we handle that by mapping the accent to a stress pattern
-- and then to the accented version in determine_stress_variant())
if decl ~= "е́" then
decl = com.remove_accents(decl)
end
local decl_aliases = old and declensions_old_aliases or declensions_aliases
local decl_cats = old and declensions_old_cat or declensions_cat
if decl_aliases[decl] then
-- If we find an alias, map it.
decl = decl_aliases[decl]
elseif not decl_cats[decl] then
error("Unrecognized declension class " .. decl)
end
return decl
end
return map_decl(decl, do_canon)
end
-- Attempt to determine the actual declension (including plural variants)
-- based on a combination of the declension the user specified, what can be
-- detected from the lemma, and special case (1), if given in the declension.
-- DECL is the value the user passed for the declension field, after
-- extraneous annotations (special cases (1) and (2), * for reducible,
-- ё for ё/ё alternation and a ; that may precede ё) have been stripped off.
-- What's left is one of the following:
--
-- 1. Blank, meaning to autodetect the declension from the lemma
-- 2. A hyphen followed by a declension variant (-ья, -ин, -ишко, -ище; see
-- long comment at top of file)
-- 3. A gender (m, f, n, 3f)
-- 4. A gender plus declension variant (e.g. f-ья)
-- 5. An actual declension, possibly including a plural variant (e.g. о-и) or
-- a slash declension (e.g. я/-ья, used for the noun дядя).
--
-- Return seven args: stem (lemma minus ending), translit, canonicalized
-- declension, explicitly specified gender if any (m, f, n or nil), whether
-- the specified declension or detected ending was accented, whether the
-- detected ending was pl, and whether the declension was autodetected
-- (corresponds to cases where a full word with ending attached is required
-- in the lemma field). "Canonicalized" means after autodetection, with
-- accents removed, with any aliases mapped to their canonical versions
-- and with any requested declension variants applied. The result is either a
-- declension that will have a categorization entry (in declensions_cat[] or
-- declensions_old_cat[]) or a slash declension where each part similarly has
-- a categorization entry.
--
-- Note that gender is never required when an explicit declension is given,
-- and in connection with stem autodetection is required only when the lemma
-- either ends in -ь or is plural.
determine_decl = function(lemma, tr, decl, args)
-- Assume we're passed a value for DECL of types 1-4 above, and
-- fetch gender and requested declension variant.
local stem
local want_ya_plural, orig_pl_ending, variant
local was_autodetected
local gender = rmatch(decl, "^(3?[mfn]?)$")
if not gender then
gender, variant = rmatch(decl, "^(3?[mfn]?)(%-[^%-]+)$")
-- But be careful with explicit declensions like -а that look like
-- variants without gender (FIXME, eventually we should maybe do
-- something about the potential ambiguity).
if gender == "" and not m_table.contains({"-ья", "-ин", "-ишко", "-ище"}, variant) then
gender, variant = nil, nil
end
end
-- If DECL is of type 1-4, handle declension variants and detect
-- the actual declension from the lemma.
if gender then
-- Check for declension variants
if variant then
if variant == "-ья" then
want_ya_plural = "-ья"
else
-- Sanity-check remaining declension variants, which need
-- specific values of animacy, gender and special-case (1)
local sc1_needed
local animate_needed
if variant == "-ишко" then
animate_needed = false
sc1_needed = true
elseif variant == "-ище" then
animate_needed = true
sc1_needed = true
elseif variant == "-ин" then
animate_needed = true
sc1_needed = false
else
-- WARNING: If adding another variant, you need to also
-- add to the list farther above.
error("Unrecognized declension variant " .. variant .. ", should be -ья, -ин, -ишко or -ище")
end
if sc1_needed and not args.want_sc1 then
error("Declension variant " .. variant .. " must be used with special case (1)")
elseif sc1_needed == false and args.want_sc1 then
error("Declension variant " .. variant .. " must not be used with special case (1)")
end
if animate_needed and args.thisa ~= "a" then
error("Declension variant " .. variant .. " must be specified as animate")
elseif animate_needed == false and args.thisa == "a" then
error("Declension variant " .. variant .. " must not be specified as animate")
end
if gender ~= "" and gender ~= "m" then
error("Declension variant " .. variant .. " should be used with the masculine gender")
end
end
end
stem, tr, decl, orig_pl_ending = detect_lemma_type(lemma, tr, gender,
args, variant)
was_autodetected = true
else
stem, tr = lemma, tr
end
-- Now canonicalize gender
if gender == "3f" then
gender = "f"
elseif gender == "" then
gender = nil
end
-- The ending should be treated as accented if either the original singular
-- or plural ending was accented, or if the stem is non-syllabic.
local was_accented = com.is_stressed(decl) or
orig_pl_ending and com.is_stressed(orig_pl_ending) or
com.is_nonsyllabic(stem)
local was_plural = not not orig_pl_ending
decl = canonicalize_decl(decl, args.old)
-- The rest of this code concerns plural variants. It's somewhat
-- complicated because there are potentially four sources of plural
-- variants (not to mention plural variants constructed using slash
-- notation):
--
-- 1. A user-requested plural variant in declension types 2 or 4 above
-- (currently only -ья)
-- 2. An explicit plural variant encoded in an explicit declension of
-- type 5 above
-- 3. An autodetected plural variant (which will happen in some cases
-- when autodetection is performed on a nominative plural)
-- 4. A plural variant derived using special case (1).
--
-- Up to three actual plural variants might exist (e.g. if the user
-- specifies a DECL value or 'm-ья(1)' and a STEM ending in -а,
-- although not all three can ever be compatible because -ья and (1)
-- are never compatible). We can't have all four because if there's
-- an explicit plural variant, there won't be a user-requested or
-- autodetected plural variant.
--
-- The goal below is to do two things: Check that all available plural
-- variants are the same, and generate the actual declension.
-- If we have a type-2 or type-3 variant, we already have the actual
-- declension; else we need to use a table to map the basic declension
-- to the one with the plural variant encoded in it.
--
-- NOTE: The code below was written with a more general plural-variant
-- system. It probably can be simplified a lot now.
-- 1: Handle explicit decl with slash variant
if rfind(decl, "/") then
if want_ya_plural then
-- Don't think this can happen
error("Plural variant " .. want_ya_plural .. " not compatible with slash declension " .. decl)
end
if args.want_sc1 then
error("Special case (1) not compatible with slash declension" .. decl)
end
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- 2: Retrieve explicitly specified or autodetected decl and pl. variant
local basic_decl, detected_or_explicit_plural = rmatch(decl, "^(.*)(%-[^mf]+)$")
if basic_decl == "ь" then
basic_decl = "ь-m"
end
basic_decl = basic_decl or decl
-- 3: Any user-requested plural variant must agree with explicit or
-- autodetected variant.
if want_ya_plural and detected_or_explicit_plural and want_ya_plural ~= detected_or_explicit_plural then
error("Plural variant " .. want_ya_plural .. " requested but plural variant " .. detected_or_explicit_plural .. " detected from plural stem")
end
-- 4: Handle special case (1). Derive the full declension, make sure its
-- plural variant matches any other available plural variants, and
-- return the declension.
if args.want_sc1 then
local sc1_decl = special_case_1_to_plural_variant[basic_decl] or
error("Special case (1) not compatible with declension " .. basic_decl)
local sc1_plural = rsub(sc1_decl, "^.*%-", "-")
local other_plural = want_ya_plural or detected_or_explicit_plural
if other_plural and sc1_plural ~= other_plural then
error("Plural variant " .. other_plural .. " specified or detected, but special case (1) calls for plural variant " .. sc1_plural)
end
return stem, tr, sc1_decl, gender, was_accented, was_plural, was_autodetected
end
-- 5: Handle user-requested plural variant without explicit or detected
-- one. (If an explicit or detected one exists, we've already checked
-- that it agrees with the user-requested one, and so we already have
-- our full declension.)
if want_ya_plural and not detected_or_explicit_plural then
local variant_decl
if plural_variant_detection_map[decl] then
variant_decl = plural_variant_detection_map[decl][want_ya_plural]
end
if variant_decl then
return stem, tr, variant_decl, gender, was_accented, was_plural, was_autodetected
else
return stem, tr, decl .. (args.old and "/ъ-ья" or "/-ья"), gender, was_accented, was_plural, was_autodetected
end
end
-- 6: Just return the full declension, which will include any available
-- plural variant in it.
return stem, tr, decl, gender, was_accented, was_plural, was_autodetected
end
-- Convert soft adjectival declensions into hard ones following certain
-- stem-final consonants. FIXME: We call this in two places, once
-- to handle auto-detection and once to handle explicit declensions; but
-- in the former case we end up calling it twice.
local function determine_adj_stem_variant(decl, stem)
local iend = rmatch(decl, "^%+[іи]([йея]?)$")
-- Convert ій/ий to ый after velar or sibilant. This is important for
-- velars; doesn't really matter one way or the other for sibilants as
-- the sibilant rules will convert both sets of endings to the same
-- thing (whereas there will be a difference with о vs. е for velars).
if iend and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl = "+ы" .. iend
-- The following is necessary for -ц, unclear if makes sense for
-- sibilants. (Would be necessary -- I think -- if we were
-- inferring short adjective forms, but we're not.)
elseif decl == "+ее" and rfind(stem, "[" .. com.sib_c .. "]$") then
decl = "+ое"
end
return decl
end
-- Attempt to determine the actual adjective declension based on a
-- combination of the declension the user specified and what can be detected
-- from the stem. DECL is the value the user passed for the declension field,
-- after extraneous annotations have been removed (although none are probably
-- relevant here). What's left is one of the following, which always begins
-- with +:
--
-- 1. +, meaning to autodetect the declension from the stem
-- 2. +ь, same as + but selects +ьий instead of +ий if lemma ends in -ий
-- 3. +short, +mixed or +proper, with the declension partly specified but
-- the particular gender/number-specific short/mixed variant to be
-- autodetected
-- 4. A gender (+m, +f or +n), used only for detecting the singular of
-- plural-form lemmas (this is primarily used in conjunction with template
-- ru-noun+, to explicitly specify the gender; for the actual declension,
-- it doesn't much matter what singular gender we pick since we're a
-- plural only)
-- 5. A gender plus short/mixed/proper/ь (e.g. +f-mixed), again with the gender
-- used only for detecting the singular of plural-form short/mixed lemmas
-- 6. An actual declension, possibly including a slash declension
-- (WARNING: Unclear if slash declensions will work, especially those
-- that are adjective/noun combinations)
--
-- Returns the same seven args as for determine_decl(). The returned
-- declension will always begin with +.
detect_adj_type = function(lemma, tr, decl, old)
local was_autodetected
local base, ending
local basedecl, g = rmatch(decl, "^(%+)([mfn])$")
if not basedecl then
g, basedecl = rmatch(decl, "^%+([mfn])%-([a-zь]+)$")
if basedecl then
basedecl = "+" .. basedecl
end
end
decl = basedecl or decl
if decl == "+" or decl == "+ь" then
local loc = rfind(lemma, "[аеиіоыя][" .. AC .. GR .. "]?[йея]$") or rfind(lemma, "ь[йея]$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
end
if ending == "ий" and decl == "+ь" then
decl = "+ьий"
elseif ending == "ій" and decl == "+ь" then
decl = "+ьій"
elseif ending then
decl = "+" .. ending
else
local loc, shortmixed = rfind(lemma, "[аоы][" .. AC .. GR .. "]?$") or rfind(lemma, "ъ?$")
if loc then
base, ending = usub(lemma, 1, loc - 1), usub(lemma, loc)
shortmixed = rfind(base, "^[" .. com.uppercase .. "].*[иы]" .. AC .. "н$") and "stressed-proper" or -- accented
rfind(base, "^[" .. com.uppercase .. "].*[иы]н$") and "proper" or --not accented
rlfind(base, "[ёео][" .. AC .. GR .. "]?в$") and "short" or
rlfind(base, "[ыи]" .. AC .. "н$") and "stressed-short" or -- accented
rlfind(base, "[ыи]н$") and "mixed" --not accented
end
if not shortmixed then
error("Cannot determine stem type of adjective: " .. lemma)
end
decl = "+" .. ending .. "-" .. shortmixed
end
was_autodetected = true
elseif m_table.contains({"+short", "+mixed", "+proper"}, decl) then
base, ending = rmatch(lemma, "^(.-)([оаыъ]?[" .. AC .. GR .. "]?)$")
assert(base)
local shortmixed = usub(decl, 2)
if rlfind(base, "[ыи]" .. AC .. "н$") then -- accented
if shortmixed == "short" then shortmixed = "stressed-short"
elseif shortmixed == "proper" then shortmixed = "stressed-proper"
end
end
decl = "+" .. ending .. "-" .. shortmixed
was_autodetected = true
else
base = lemma
end
if ending and ending ~= "" then
tr = com.strip_tr_ending(tr, ending)
end
-- Remove any accents from the declension, but not their presence.
-- We will convert was_accented into stress pattern b, and convert that
-- back to an accented version in determine_stress_variant(). This way
-- we end up with the stressed version whether the user placed an accent
-- in the ending or decl or specified stress pattern b.
-- FIXME, might not work in the presence of slash declensions
local was_accented = com.is_stressed(decl)
decl = com.remove_accents(decl)
decl = map_decl(decl, function(decl)
return determine_adj_stem_variant(decl, base)
end)
local singdecl
if decl == "+ые" then
singdecl = (g == "m" or not g) and (was_accented and "+ой" or "+ый") or not old and g == "f" and "+ая" or not old and g == "n" and "+ое"
elseif decl == "+ыя" and old then
singdecl = (g == "f" or not g) and "+ая" or g == "n" and "+ое"
elseif decl == "+ие" and not old then
singdecl = (g == "m" or not g) and "+ий" or g == "f" and "+яя" or g == "n" and "+ее"
elseif decl == "+іе" and old and (g == "m" or not g) then
singdecl = "+ій"
elseif decl == "+ія" and old then
singdecl = (g == "f" or not g) and "+яя" or g == "n" and "+ее"
elseif decl == "+ьи" then
singdecl = (g == "m" or not g) and (old and "+ьій" or "+ьий") or g == "f" and "+ья" or g == "n" and "+ье"
elseif rfind(decl, "^%+ы%-") then -- decl +ы-mixed or similar
local beg = (g == "m" or not g) and (old and "ъ" or "") or g == "f" and "а" or g == "n" and "о"
singdecl = beg and "+" .. beg .. usub(decl, 3)
end
if singdecl then
was_plural = true
decl = singdecl
end
return base, tr, canonicalize_decl(decl, old), g, was_accented, was_plural, was_autodetected
end
-- If stress pattern omitted, detect it based on whether ending is stressed
-- or the decl class or stem accent calls for inherent stress, defaulting to
-- pattern a. This is run after alias resolution and accent removal of DECL;
-- WAS_ACCENTED indicates whether the ending was originally stressed.
-- FIXME: This is run before splitting slash patterns but should be run after.
detect_stress_pattern = function(stem, decl, decl_cats, reducible,
was_plural, was_accented)
-- ёнок and ёночек always bear stress
if rfind(decl, "ёнокъ?") or rfind(decl, "ёночекъ?") then
return "b"
-- stressed suffix и́н; missing in plural and true endings don't bear stress
-- (except for exceptional господи́н)
elseif rfind(decl, "инъ?") and was_accented then
return "d"
-- Adjectival -ой always bears the stress
elseif rfind(decl, "%+ой") then
return "b"
-- Adjectival stressed-short, stressed-proper bears the stress
elseif rfind(decl, "^%+.*%-stressed") then
return "b"
-- Pattern b if ending was accented by user
elseif was_accented then
return "b"
-- Nonsyllabic stem means pattern b
elseif com.is_nonsyllabic(stem) then
return "b"
-- Accent on reducible vowel in masc nom sg (not plural) means pattern b.
-- Think about whether we want to enable this.
-- elseif reducible and not was_plural then
-- -- FIXME hack. Eliminate plural part of slash declension.
-- decl = rsub(decl, "/.*", "")
-- if decl_cats[decl] and decl_cats[decl].g == "m" then
-- if com.is_ending_stressed(stem) or com.is_monosyllabic(stem) then
-- return "b"
-- end
-- end
end
return "a"
end
-- In certain special cases, depending on the declension, we override the
-- user-specified stress pattern and convert it to something else.
-- NOTE: This function is run after alias resolution and accent removal.
-- FIXME: It's also run before splitting slash patterns but should be run after.
override_stress_pattern = function(decl, stress)
-- ёнок and ёночек always bear stress; if user specified a,
-- convert to b. Don't do this with slash patterns (see FIXME above).
if stress == "a" and (rfind(decl, "^ёнокъ?$") or rfind(decl, "^ёночекъ?$")) then
return "b"
end
return stress
end
-- Canonicalize an adjectival declension to either the stressed or unstressed
-- variant depending on the stress. Ultimately this is what ensures that
-- the user's stress mark on an adjectival ending is respected.
determine_stress_variant = function(decl, stress)
if stress == "b" then
if decl == "+ая" then
return "+а́я"
elseif decl == "+ое" then
return "+о́е"
else
-- Convert +...-short to +...-stressed-short and same for -proper
local b, e = rmatch(decl, "^%+(.*)%-(short)$")
if not b then
b, e = rmatch(decl, "^%+(.*)%-(proper)$")
end
if b and not rfind(b, "%-stressed") then
return "+" .. b .. "-stressed-" .. e
end
end
end
return decl
end
-- Canonicalize a declension based on the final stem consonant, in
-- particular converting soft declensions to hard ones after velars and/or
-- sibilants. FIXME: We also do this canonicalization earlier on during
-- auto-detection (determine_adj_stem_variant() is called by
-- detect_adj_type(), and code in detect_lemma_type() does the equivalent
-- of the first clause below). Doing it here ensures that explicitly
-- specified declensions get handled as well, but it would be nice to not
-- do the same thing twice in the auto-detection case.
determine_stem_variant = function(decl, stem)
if decl == "е" and rfind(stem, "[" .. com.sib_c .. "]$") then
return "о"
end
return determine_adj_stem_variant(decl, stem)
end
is_reducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "3rd" and decl_cat.g == "f" or decl_cat.g == "m" then
return true
else
return false
end
end
-- Reduce nom sg to stem by eliminating the "epenthetic" vowel. Applies to
-- masculine 2nd-declension hard and soft, and 3rd-declension feminine in
-- -ь. STEM and DECL are after determine_decl(), before converting
-- outward-facing declensions to inward ones.
function export.reduce_nom_sg_stem(stem, tr, decl, soft_n, can_err)
local full_stem = stem .. (decl == "й" and decl or "")
local full_tr = tr and tr .. (decl == "й" and "j" or "")
local ret, rettr = com.reduce_stem(full_stem, full_tr, soft_n)
if not ret and can_err then
error("Unable to reduce stem " .. stem)
end
return ret, rettr
end
is_dereducible = function(decl_cat)
if decl_cat.suffix or decl_cat.cant_reduce or decl_cat.adj then
return false
elseif decl_cat.decl == "1st" or decl_cat.decl == "2nd" and decl_cat.g == "n" then
return true
else
return false
end
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. dereducible nouns
-- in -ня.
add_bare_suffix = function(bare, baretr, old, sgdc, dereduced)
if old and sgdc.hard == "hard" then
-- Final -ъ isn't transliterated
return bare .. "ъ", baretr
elseif sgdc.hard == "soft" or sgdc.hard == "palatal" then
-- This next clause corresponds to a special case in Vitalik's module.
-- It says that nouns in -ня (accent class a) have gen pl without
-- trailing -ь. It appears to apply to most nouns in -ня (possibly
-- all in -льня), but ку́хня (gen pl ку́хонь) and дерéвня (gen pl
-- дереве́нь) is an exception. (Vitalik's module has an extra
-- condition here 'stress == "a"' that would exclude дере́вня but I
-- don't think this condition is in Zaliznyak, as he indicates
-- дере́вня as having an exceptional genitive plural.)
if dereduced and rfind(bare, "[нН]$") and sgdc.decl == "1st" then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
-- Final -ъ isn't transliterated
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
return bare .. "й", baretr and (baretr .. "j")
else
return bare .. "ь", baretr and (baretr .. "ʹ")
end
else
return bare, baretr
end
end
-- Dereduce stem to the form found in the gen pl (and maybe nom sg) by
-- inserting an epenthetic vowel. Applies to 1st declension and 2nd
-- declension neuter, and to 2nd declension masculine when the stem was
-- specified as a plural form (in which case we're deriving the nom sg,
-- and also the gen pl in the alt-gen-pl scenario). STEM and DECL are
-- after determine_decl(), before converting outward-facing declensions
-- to inward ones. STRESS is the stess pattern.
function export.dereduce_nom_sg_stem(stem, tr, sgdc, stress, old, can_err)
local epenthetic_stress = ending_stressed_gen_pl_patterns[stress]
local ret, rettr = com.dereduce_stem(stem, tr, epenthetic_stress)
if not ret then
if can_err then
error("Unable to dereduce stem " .. stem)
else
return nil, nil
end
end
return add_bare_suffix(ret, rettr, old, sgdc, true)
end
--------------------------------------------------------------------------
-- Second-declension masculine --
--------------------------------------------------------------------------
----------------- Masculine hard -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style).
declensions_old["ъ"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and "е́й" or "о́въ"
end,
["alt_gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["ъ"] = { decl="2nd", hard="hard", g="m" }
-- Normal mapping of old ъ would be "" (blank), but we set up "#" as an alias
-- so we have a way of referring to it without defaulting if need be and
-- distinct from auto-detection (e.g. in the second stem of a word, or to
-- override autodetection of -ёнок or -ин -- the latter is necessary in the
-- case of семьянин).
declensions_aliases["#"] = ""
----------------- Masculine hard, irregular plural -------------------
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg nom pl -а.
declensions_old["ъ-а"] = mw.clone(declensions_old["ъ"])
declensions_old["ъ-а"]["nom_pl"] = "а́"
declensions_old_cat["ъ-а"] = { decl="2nd", hard="hard", g="m", alt_nom_pl=true }
declensions_aliases["#-a"] = "-a"
-- Hard-masculine declension, ending in a hard consonant
-- (ending in -ъ, old-style), with irreg soft pl -ья.
-- Differs from the normal declension throughout the plural.
declensions_old["ъ-ья"] = {
["nom_sg"] = "ъ",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = nil,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = "ьёвъ",
["alt_gen_pl"] = "е́й",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ъ-ья"] = { decl="2nd", hard="hard", g="m", irregpl=true }
declensions_aliases["#-ья"] = "-ья"
----------------- Masculine hard, suffixed, irregular plural -------------------
declensions_old["инъ"] = {
["nom_sg"] = "и́нъ",
["gen_sg"] = "и́на",
["dat_sg"] = "и́ну",
["acc_sg"] = nil,
["ins_sg"] = "и́номъ",
["pre_sg"] = "и́нѣ",
["nom_pl"] = "е́",
["gen_pl"] = "ъ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["инъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old["ёнокъ"] = {
["nom_sg"] = "ёнокъ",
["gen_sg"] = "ёнка",
["dat_sg"] = "ёнку",
["acc_sg"] = nil,
["ins_sg"] = "ёнкомъ",
["pre_sg"] = "ёнкѣ",
["nom_pl"] = "я́та",
["gen_pl"] = "я́тъ",
["dat_pl"] = "я́тамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тами",
["pre_pl"] = "я́тахъ",
}
declensions_old_cat["ёнокъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["онокъ"] = "ёнокъ"
declensions_old_aliases["енокъ"] = "ёнокъ"
declensions_old["ёночекъ"] = {
["nom_sg"] = "ёночекъ",
["gen_sg"] = "ёночка",
["dat_sg"] = "ёночку",
["acc_sg"] = nil,
["ins_sg"] = "ёночкомъ",
["pre_sg"] = "ёночкѣ",
["nom_pl"] = "я́тки",
["gen_pl"] = "я́токъ",
["dat_pl"] = "я́ткамъ",
["acc_pl"] = nil,
["ins_pl"] = "я́тками",
["pre_pl"] = "я́ткахъ",
}
declensions_old_cat["ёночекъ"] = { decl="2nd", hard="hard", g="m", suffix=true }
declensions_old_aliases["оночекъ"] = "ёночекъ"
declensions_old_aliases["еночекъ"] = "ёночекъ"
----------------- Masculine soft -------------------
-- Normal soft-masculine declension in -ь
declensions_old["ь-m"] = {
["nom_sg"] = "ь",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["alt_gen_pl"] = "ь",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-m"] = { decl="2nd", hard="soft", g="m" }
-- Soft-masculine declension in -ь with irreg nom pl -я
declensions_old["ь-я"] = mw.clone(declensions_old["ь-m"])
declensions_old["ь-я"]["nom_pl"] = "я́"
declensions_old_cat["ь-я"] = { decl="2nd", hard="soft", g="m", alt_nom_pl=true }
----------------- Masculine palatal -------------------
-- Masculine declension in palatal -й
declensions_old["й"] = {
["nom_sg"] = "й",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = nil,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = "ёвъ",
["alt_gen_pl"] = "й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["й"] = { decl="2nd", hard="palatal", g="m" }
declensions_old["й-я"] = mw.clone(declensions_old["й"])
declensions_old["й-я"]["nom_pl"] = "я́"
declensions_old_cat["й-я"] = { decl="2nd", hard="palatal", g="m", alt_nom_pl=true }
--------------------------------------------------------------------------
-- First-declension feminine --
--------------------------------------------------------------------------
----------------- Feminine hard -------------------
-- Hard-feminine declension in -а
declensions_old["а"] = {
["nom_sg"] = "а́",
["gen_sg"] = "ы́",
["dat_sg"] = "ѣ́",
["acc_sg"] = "у́",
["ins_sg"] = {"о́й<insa>", "о́ю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ѣ́",
["nom_pl"] = "ы́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["а"] = { decl="1st", hard="hard", g="f" }
----------------- Feminine soft -------------------
-- Soft-feminine declension in -я
declensions_old["я"] = {
["nom_sg"] = "я́",
["gen_sg"] = "и́",
["dat_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_dat_sg_patterns[stress] and "и" or "ѣ́"
end,
["acc_sg"] = "ю́",
["ins_sg"] = {"ёй<insa>", "ёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "и́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "]́?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["я"] = { decl="1st", hard="soft", g="f" }
-- Soft-feminine declension in -ья.
-- Almost like ь + -я endings except for genitive plural.
declensions_old["ья"] = {
["nom_sg"] = "ья́",
["gen_sg"] = "ьи́",
["dat_sg"] = "ьѣ́",
["acc_sg"] = "ью́",
["ins_sg"] = {"ьёй<insa>", "ьёю<insb>"}, -- see concat_word_forms_1()
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ьи́",
["gen_pl"] = function(stem, stress)
-- circumflex accent is a signal that forces stress, particularly
-- in accent pattern d/d'.
return (ending_stressed_gen_pl_patterns[stress] or stress == "d" or stress == "d'") and "е̂й" or "ий"
end,
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ья"] = {
decl="1st", hard="soft", g="f",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
--------------------------------------------------------------------------
-- Second-declension neuter --
--------------------------------------------------------------------------
----------------- Neuter hard -------------------
-- Normal hard-neuter declension in -о
declensions_old["о"] = {
["nom_sg"] = "о́",
["gen_sg"] = "а́",
["dat_sg"] = "у́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "о́" or nil
end,
["ins_sg"] = "о́мъ",
["pre_sg"] = "ѣ́",
["nom_pl"] = "а́",
["gen_pl"] = function(stem, stress)
return nom.sibilant_suffixes[ulower(usub(stem, -1))] and ending_stressed_gen_pl_patterns[stress] and "е́й" or "ъ"
end,
["alt_gen_pl"] = "о́въ",
["dat_pl"] = "а́мъ",
["acc_pl"] = nil,
["ins_pl"] = "а́ми",
["pre_pl"] = "а́хъ",
}
declensions_old_cat["о"] = { decl="2nd", hard="hard", g="n" }
-- Hard-neuter declension in -о with irreg nom pl -и
declensions_old["о-и"] = mw.clone(declensions_old["о"])
declensions_old["о-и"]["nom_pl"] = "ы́"
declensions_old_cat["о-и"] = { decl="2nd", hard="hard", g="n", alt_nom_pl=true }
declensions_old_aliases["о-ы"] = "о-и"
-- Masculine-gender neuter-form declension in -(ишк)о with irreg nom pl -и,
-- with colloquial feminine endings in some of the singular cases
-- (§5 p. 74 of Zaliznyak)
declensions_old["(ишк)о-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ишк)о-и"]["gen_sg"] = {"а́", "ы́1"}
declensions_old["(ишк)о-и"]["dat_sg"] = {"у́", "ѣ́1"}
declensions_old["(ишк)о-и"]["ins_sg"] = {"о́мъ", "о́й1"}
declensions_old_cat["(ишк)о-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ишк)о-и"] = "<sup>1</sup> Colloquial."
-- Masculine-gender animate neuter-form declension in -(ищ)е with irreg
-- nom pl -и, with colloquial feminine endings in some of the singular cases
-- (§4 p. 74 of Zaliznyak)
declensions_old["(ищ)е-и"] = mw.clone(declensions_old["о-и"])
declensions_old["(ищ)е-и"]["acc_sg"] = {"а́", "у́1"}
declensions_old["(ищ)е-и"]["gen_sg"] = {"а́", "ы́2"}
declensions_old["(ищ)е-и"]["dat_sg"] = {"у́", "ѣ́2"}
declensions_old["(ищ)е-и"]["ins_sg"] = {"о́мъ", "о́й2"}
declensions_old_cat["(ищ)е-и"] = { decl="2nd", hard="hard", g="n", colloqfem=true, alt_nom_pl=true }
internal_notes_table_old["(ищ)е-и"] = "<sup>1</sup> Colloquial.<br /><sup>2</sup> Less common, more colloquial."
----------------- Neuter soft -------------------
-- Soft-neuter declension in -е (stressed -ё)
declensions_old["е"] = {
["nom_sg"] = "ё",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ё" or nil
end,
["ins_sg"] = "ёмъ",
["pre_sg"] = function(stem, stress)
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and not ending_stressed_pre_sg_patterns[stress] and "и" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and not rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "е́й" or "й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е"] = {
singular = function(suffix)
if suffix == "ё" then
return "ending in -ё"
else
return {}
end
end,
decl="2nd", hard="soft", g="n", gensg=true
}
-- User-facing declension type "ё" = "е"
declensions_old_aliases["ё"] = "е"
-- Rare soft-neuter declension in stressed -е́ (e.g. муде́, бытие́)
declensions_old["е́"] = {
["nom_sg"] = "е́",
["gen_sg"] = "я́",
["dat_sg"] = "ю́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "е́" or nil
end,
["ins_sg"] = "е́мъ",
["pre_sg"] = function(stem, stress)
-- FIXME!!! Are we sure about this condition? This is what was
-- found in the old template, but the related -е declension has
-- -ие prep sg ending -(и)и only when *not* stressed.
return rlfind(stem, "[іи][" .. AC .. GR .. "]?$") and "и́" or "ѣ́"
end,
["nom_pl"] = "я́",
["gen_pl"] = function(stem, stress)
return rlfind(stem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") and "й" or "е́й"
end,
["alt_gen_pl"] = "ёвъ",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["е́"] = {
singular = "ending in stressed -е",
decl="2nd", hard="soft", g="n", gensg=true
}
-- Soft-neuter declension in unstressed -ье (stressed -ьё).
declensions_old["ье"] = {
["nom_sg"] = "ьё",
["gen_sg"] = "ья́",
["dat_sg"] = "ью́",
["acc_sg"] = function(stem, stress, args)
return not (args.explicit_gender == "m" and args.thisa == "a") and "ьё" or nil
end,
["ins_sg"] = "ьёмъ",
["pre_sg"] = "ьѣ́",
["nom_pl"] = "ья́",
["gen_pl"] = function(stem, stress)
return ending_stressed_gen_pl_patterns[stress] and "е́й" or "ий"
end,
["alt_gen_pl"] = "ьёвъ",
["dat_pl"] = "ья́мъ",
["acc_pl"] = nil,
["ins_pl"] = "ья́ми",
["pre_pl"] = "ья́хъ",
}
declensions_old_cat["ье"] = {
decl="2nd", hard="soft", g="n",
stem_suffix="ь", gensg=true,
ignore_reduce=true -- already has dereduced gen pl
}
declensions_old_aliases["ьё"] = "ье"
--------------------------------------------------------------------------
-- Third declension --
--------------------------------------------------------------------------
declensions_old["ь-f"] = {
["nom_sg"] = "ь",
["gen_sg"] = "и́",
["dat_sg"] = "и́",
["acc_sg"] = "ь",
["ins_sg"] = "ью́",
["pre_sg"] = "и́",
["nom_pl"] = "и́",
["gen_pl"] = "е́й",
["dat_pl"] = "я́мъ",
["acc_pl"] = nil,
["ins_pl"] = "я́ми",
["pre_pl"] = "я́хъ",
}
declensions_old_cat["ь-f"] = { decl="3rd", hard="soft", g="f" }
declensions_old["мя"] = {
["nom_sg"] = "мя",
["gen_sg"] = "мени",
["dat_sg"] = "мени",
["acc_sg"] = nil,
["ins_sg"] = "менемъ",
["pre_sg"] = "мени",
["nom_pl"] = "мена́",
["gen_pl"] = "мёнъ",
["dat_pl"] = "мена́мъ",
["acc_pl"] = nil,
["ins_pl"] = "мена́ми",
["pre_pl"] = "мена́хъ",
}
declensions_old_cat["мя"] = { decl="3rd", hard="soft", g="n", cant_reduce=true }
--------------------------------------------------------------------------
-- Indeclinable --
--------------------------------------------------------------------------
-- Indeclinable declension; no endings.
declensions_old["$"] = {
["nom_sg"] = "",
["gen_sg"] = "",
["dat_sg"] = "",
["acc_sg"] = nil,
["ins_sg"] = "",
["pre_sg"] = "",
["nom_pl"] = "",
["gen_pl"] = "",
["dat_pl"] = "",
["acc_pl"] = nil,
["ins_pl"] = "",
["pre_pl"] = "",
}
declensions_old_cat["$"] = { decl="indeclinable", hard="none", g="none" }
--------------------------------------------------------------------------
-- Adjectival --
--------------------------------------------------------------------------
-- This needs to be up here because it is called just below.
local function old_to_new(v)
v = rsub(v, "ъ$", "")
v = rsub(v, "^ъ", "")
v = rsub(v, "(%A)ъ", "%1")
v = rsub(v, "ъ(%A)", "%1")
v = rsub(v, "і", "и")
v = rsub(v, "ѣ", "е")
return v
end
-- Meaning of entry is:
-- 1. The declension name in module ru-adjective
-- 2. The masculine declension name in this module
-- 3. The neuter declension name in this module
-- 4. The feminine declension name in this module
-- 5. The value of hard= for the declensions_cat entry
-- 6. The value of decl= for the declensions_cat entry
-- 7. The value of possadj= for the declensions_cat entry (true if possessive
-- or similar type of adjective)
local adj_decl_map = {
{"ый", "ый", "ое", "ая", "hard", "long", false},
{"ій", "ій", "ее", "яя", "soft", "long", false},
{"ой", "ой", "о́е", "а́я", "hard", "long", false},
{"ьій", "ьій", "ье", "ья", "palatal", "long", true},
{"short", "ъ-short", "о-short", "а-short", "hard", "short", true},
{"mixed", "ъ-mixed", "о-mixed", "а-mixed", "hard", "mixed", true},
{"proper", "ъ-proper", "о-proper", "а-proper", "hard", "proper", true},
{"stressed-short", "ъ-stressed-short", "о-stressed-short", "а-stressed-short", "hard", "short", true},
{"stressed-proper", "ъ-stressed-proper", "о-stressed-proper", "а-stressed-proper", "hard", "proper", true},
}
local function get_adjectival_decl(adjtype, gender, old)
local decl, intnotes = m_ru_adj.get_nominal_decl(adjtype, gender, old)
-- hack fem ins_sg to insert <insa>, <insb>; see concat_word_forms_1()
if gender == "f" and type(decl["ins_sg"]) == "table" and #decl["ins_sg"] == 2 then
decl["ins_sg"][1] = decl["ins_sg"][1] .. "<insa>"
decl["ins_sg"][2] = decl["ins_sg"][2] .. "<insb>"
end
return decl, intnotes
end
for _, declspec in ipairs(adj_decl_map) do
local oadjdecl = declspec[1]
local nadjdecl = old_to_new(oadjdecl)
local odecl_by_gender =
{m="+" .. declspec[2], n="+" .. declspec[3], f="+" .. declspec[4]}
local hard = declspec[5]
local decltype = declspec[6]
local possadj = declspec[7]
for _, g in ipairs({"m", "n", "f"}) do
local odecl = odecl_by_gender[g]
local ndecl = old_to_new(odecl)
declensions_old[odecl], internal_notes_table_old[odecl] =
get_adjectival_decl(oadjdecl, g, true)
declensions[ndecl], internal_notes_table[ndecl] =
get_adjectival_decl(nadjdecl, g, false)
declensions_old_cat[odecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
declensions_cat[ndecl] = {
decl=decltype, hard=hard, g=g, adj=true, possadj=possadj }
end
end
-- Set up some aliases.
declensions_old_aliases["+о́-short"] = "+о-stressed-short"
declensions_old_aliases["+а́-short"] = "+а-stressed-short"
declensions_old_aliases["+о́-proper"] = "+о-stressed-proper"
declensions_old_aliases["+а́-proper"] = "+а-stressed-proper"
declensions_aliases["+#-short"] = "+-short"
declensions_aliases["+#-mixed"] = "+-mixed"
declensions_aliases["+#-proper"] = "+-proper"
declensions_aliases["+#-stressed-short"] = "+-stressed-short"
declensions_aliases["+#-stressed-proper"] = "+-stressed-proper"
--------------------------------------------------------------------------
-- Populate new from old --
--------------------------------------------------------------------------
-- Function to convert an entry in an old declensions table to new.
local function old_decl_entry_to_new(v)
if not v then
return nil
elseif type(v) == "table" then
local new_entry = {}
for _, i in ipairs(v) do
table.insert(new_entry, old_decl_entry_to_new(i))
end
return new_entry
elseif type(v) == "function" then
return function(stem, suffix, args)
return old_decl_entry_to_new(v(stem, suffix, args))
end
else
return old_to_new(v)
end
end
-- Function to convert an old declensions table to new.
local function old_decl_to_new(odecl)
local ndecl = {}
for k, v in pairs(odecl) do
ndecl[k] = old_decl_entry_to_new(v)
end
return ndecl
end
-- Function to convert an entry in an old declensions_cat table to new.
local function old_decl_cat_entry_to_new(odecl_cat_entry)
if not odecl_cat_entry then
return nil
elseif type(odecl_cat_entry) == "function" then
return function(suffix)
return old_decl_cat_entry_to_new(odecl_cat_entry(suffix))
end
elseif type(odecl_cat_entry) == "table" then
local ndecl_cat_entry = {}
for k, v in pairs(odecl_cat_entry) do
ndecl_cat_entry[k] = old_decl_cat_entry_to_new(v)
end
return ndecl_cat_entry
elseif type(odecl_cat_entry) == "boolean" then
return odecl_cat_entry
else
assert(type(odecl_cat_entry) == "string")
return old_to_new(odecl_cat_entry)
end
end
-- Function to convert an old declensions_cat table to new.
local function old_decl_cat_to_new(odeclcat)
local ndeclcat = {}
for k, v in pairs(odeclcat) do
ndeclcat[k] = old_decl_cat_entry_to_new(v)
end
return ndeclcat
end
-- populate declensions[] from declensions_old[]
for odecltype, odecl in pairs(declensions_old) do
local ndecltype = old_to_new(odecltype)
if not declensions[ndecltype] then
declensions[ndecltype] = old_decl_to_new(odecl)
end
end
-- populate declensions_cat[] from declensions_old_cat[]
for odecltype, odeclcat in pairs(declensions_old_cat) do
local ndecltype = old_to_new(odecltype)
if not declensions_cat[ndecltype] then
declensions_cat[ndecltype] = old_decl_cat_to_new(odeclcat)
end
end
-- populate declensions_aliases[] from declensions_old_aliases[]
for ofrom, oto in pairs(declensions_old_aliases) do
local from = old_to_new(ofrom)
if not declensions_aliases[from] then
declensions_aliases[from] = old_to_new(oto)
end
end
-- populate internal_notes_table[] from internal_notes_table_old[]
for odecl, note in pairs(internal_notes_table_old) do
local ndecl = old_to_new(odecl)
if not internal_notes_table[ndecl] then
-- FIXME, should we be calling old_to_new() here?
internal_notes_table[ndecl] = note
end
end
--------------------------------------------------------------------------
-- Inflection functions --
--------------------------------------------------------------------------
-- Attach the stressed stem (or plural stem, or barestem) out of ARGS
-- to the unstressed suffix SUF, modifying the suffix as necessary for the
-- last letter of the stem (e.g. if it is velar, sibilant or ц). CASE is
-- the case form being created and is used to select the plural stem if
-- needed. Returns two values, the combined form and the modified suffix.
local function attach_unstressed(args, case, suf, was_stressed)
if suf == nil then
return nil, nil
elseif rfind(suf, CFLEX) then -- if suf has circumflex accent, it forces stressed
return attach_stressed(args, case, suf)
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.pl, args.pltr
end
if not stem and case == "ins_sg" then
stem, tr = args.ins_sg_stem, args.ins_sg_tr
end
if not stem then
stem, tr = args.stem, args.stemtr
end
if nom.nonsyllabic_suffixes[suf] then
-- If gen_pl, use special args.gen_pl_bare if given, else regular
-- args.bare if there isn't a plural stem. If nom_sg, always use
-- regular args.bare.
local barearg, bareargtr
if case == "gen_pl" then
barearg, bareargtr = args.gen_pl_bare, args.gen_pl_baretr
if not barearg and args.pl == args.stem then
barearg, bareargtr = args.bare, args.baretr
end
else
barearg, bareargtr = args.bare, args.baretr
end
local barestem = barearg or stem
local barestem, baretr
if barearg then
barestem, baretr = barearg, bareargtr
else
barestem, baretr = stem, tr
end
if was_stressed and case == "gen_pl" then
if not barearg then
local gen_pl_stem, gen_pl_tr = com.make_ending_stressed(stem, tr)
barestem, baretr = gen_pl_stem, gen_pl_tr
end
end
if rlfind(barestem, "[йьъ]$") then
suf = ""
else
if suf == "ъ" then
-- OK
elseif suf == "й" or suf == "ь" then
if barearg and case == "gen_pl" then
-- explicit bare or reducible, don't add -ь
suf = ""
elseif rfind(barestem, "[" .. com.vowel .. "][" .. AC .. GR .. "]?$") then
-- not reducible, do add -ь and correct to -й if necessary
suf = "й"
else
suf = "ь"
end
end
end
return com.concat_russian_tr(barestem, baretr, suf, nil, "dopair"), suf
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Analogous to attach_unstressed() but for the unstressed stem and a
-- stressed suffix.
attach_stressed = function(args, case, suf)
if suf == nil then
return nil, nil
end
-- circumflex forces stress even when the accent pattern calls for no stress
suf = rsub(suf, "̂", AC)
if com.is_unstressed(suf) then
return attach_unstressed(args, case, suf, "was stressed")
end
local stem, tr
if rfind(case, "_pl") then
stem, tr = args.upl, args.upltr
end
if not stem then
stem, tr = args.ustem, args.ustemtr
end
local rules = nom.stressed_rules[ulower(usub(stem, -1))]
return nom.combine_stem_and_suffix(stem, tr, suf, rules, args.old)
end
-- Attach the appropriate stressed or unstressed stem (or plural stem as
-- determined by CASE, or barestem) out of ARGS to the suffix SUF, which may
-- be a list of alternative suffixes (e.g. in the inst sg of feminine nouns).
-- Calls FUN (either attach_stressed() or attach_unstressed()) to do the work
-- for an individual suffix. Returns two values, a list of combined forms
-- and a list of the real suffixes used (which may be modified from the
-- passed-in suffixes, e.g. by removing stress marks or modifying vowels in
-- various ways after a stem-final velar, sibilant or ц). Each combined form
-- is a two-element list {stem, tr} (or a one-element list if tr is nil).
-- IRREG is true if this is an irregular form. We are handling the Nth word;
-- ISLAST is true if this is the last one.
local function attach_with(args, case, suf, fun, irreg, n, islast)
if type(suf) == "table" then
local all_combineds = {}
local all_realsufs = {}
for _, x in ipairs(suf) do
local combineds, realsufs =
attach_with(args, case, x, fun, irreg, n, islast)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
for _, realsuf in ipairs(realsufs) do
table.insert(all_realsufs, realsuf)
end
end
return all_combineds, all_realsufs
else
local combined, realsuf = fun(args, case, suf)
local irregsuf = irreg and {IRREGMARKER} or {""}
return {combined and com.concat_paired_russian_tr(
com.concat_paired_russian_tr(args["prefix" .. n], combined),
com.concat_paired_russian_tr(args["suffix" .. n], irregsuf)) or nil},
{realsuf and realsuf .. args["suffix" .. n][1] or nil}
end
end
-- Generate the form(s) and suffix(es) for CASE according to the declension
-- table DECL, using the attachment function FUN (one of attach_stressed()
-- or attach_unstressed()). IS_SLASH is true if this is a slash declension
-- (different declensions for singular and plural). We are handling the Nth
-- word; ISLAST is true if this is the last one.
local function gen_form(args, decl, case, stress, fun, is_slash, n, islast)
local irreg = false
if not args.suffixes[case] then
args.suffixes[case] = {}
end
local decl_sufs = args.old and declensions_old or declensions
decl_sufs = decl_sufs[decl]
local suf = decl_sufs[case]
local decl_cats = args.old and declensions_old_cat or declensions_cat
local ispl = rfind(case, "_pl")
if ispl and (decl_cats[decl].irregpl or args.pl and args.pl ~= args.stem or is_slash) then
irreg = true
end
if case == "nom_pl" and decl_cats[decl].alt_nom_pl then
irreg = true
end
if type(suf) == "function" then
suf = suf(ispl and args.pl or args.stem, stress, args)
end
if case == "gen_pl" and args.alt_gen_pl then
suf = decl_sufs.alt_gen_pl
irreg = true
if not suf then
error("No alternative genitive plural available for this declension class")
end
end
local combineds, realsufs = attach_with(args, case, suf, fun, irreg, n, islast)
for _, realsuf in ipairs(realsufs) do
args.any_non_nil[case] = true
args.this_any_non_nil[case] = true
insert_if_not(args.suffixes[case], realsuf)
end
return combineds
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
}
do_stress_pattern = function(stress, args, decl, number, n, islast)
local f = {}
for _, case in ipairs(decl_cases) do
if not number or (number == "sg" and rfind(case, "_sg")) or
(number == "pl" and rfind(case, "_pl")) then
f[case] = gen_form(args, decl, case, stress,
attachers[stress_patterns[stress][case]], not not number,
n, islast)
-- Turn empty form lists into nil to facilitate computation of
-- animate/inanimate accusatives below
if f[case] and #f[case] == 0 then
f[case] = nil
end
-- Compute linked versions of potential lemma cases, for use
-- in the ru-noun+ headword. We substitute the original lemma
-- (before removing links) for forms that are the same as the
-- lemma, if the original lemma has links.
if f[case] and (case == "nom_sg" or case == "nom_pl") then
local linked_forms = {}
for _, form in ipairs(f[case]) do
-- Return true if FORM is "close enough" to LEMMA that we can substitute the
-- linked form of the lemma. Currently this means exactly the same except that
-- we ignore acute and grave accent differences in monosyllables, and ignore
-- notes that may have been appended (e.g. the triangle marking irregularity).
local entry, notes = m_table_tools.separate_notes(form[1])
local lemma = args.lemma_no_links
local close_enough_to_lemma =
entry == lemma or (com.is_monosyllabic(entry) and
com.is_monosyllabic(lemma) and
com.remove_accents(entry) == com.remove_accents(lemma))
if close_enough_to_lemma and
rfind(args.orig_lemma, "%[%[") then
table.insert(linked_forms, {args.orig_lemma .. notes, args.lemmatr and args.lemmatr .. notes})
else
table.insert(linked_forms, form)
end
end
f[case .. "_linked"] = linked_forms
end
end
end
-- Set acc an/in variants now as appropriate. We used to do this in
-- handle_forms_and_overrides(), which simplified the handling of
-- nom/gen/acc overrides but caused problems for words like мазло and
-- трепло that had a mixture of nil and non-nil accusative forms.
local an = args.thisa
if not number or number == "sg" then
f.acc_sg_an = f.acc_sg_an or f.acc_sg or an == "i" and f.nom_sg or f.gen_sg
f.acc_sg_in = f.acc_sg_in or f.acc_sg or an == "a" and f.gen_sg or f.nom_sg
end
if not number or number == "pl" then
f.acc_pl_an = f.acc_pl_an or f.acc_pl or an == "i" and f.nom_pl or f.gen_pl
f.acc_pl_in = f.acc_pl_in or f.acc_pl or an == "a" and f.gen_pl or f.nom_pl
end
for case, forms in pairs(f) do
if not args.forms[case] then
args.forms[case] = {}
end
for _, form in ipairs(forms) do
insert_if_not(args.forms[case], form)
end
end
end
stress_patterns["a"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["b"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["b'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["c"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="+", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["d"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["d'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="-", dat_pl="-", acc_pl="-", ins_pl="-", pre_pl="-",
}
stress_patterns["e"] = {
nom_sg="-", gen_sg="-", dat_sg="-", acc_sg="-", ins_sg="-", pre_sg="-",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f'"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="-", ins_sg="+", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
stress_patterns["f''"] = {
nom_sg="+", gen_sg="+", dat_sg="+", acc_sg="+", ins_sg="-", pre_sg="+",
nom_pl="-", gen_pl="+", dat_pl="+", acc_pl="+", ins_pl="+", pre_pl="+",
}
ending_stressed_gen_pl_patterns = m_table.listToSet({"b", "b'", "c", "e", "f", "f'", "f''"})
ending_stressed_pre_sg_patterns = m_table.listToSet({"b", "b'", "d", "d'", "f", "f'", "f''"})
ending_stressed_dat_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_sg_patterns = ending_stressed_pre_sg_patterns
ending_stressed_pl_patterns = m_table.listToSet({"b", "b'", "c"})
local numbers = {
["s"] = "ကိုန်ဨကဝုစ်",
["p"] = "ကိုန်ဗဟုဝစ်",
}
local old_title_temp = [=[မလဟုတ်စှ်ေကၠာပြုပြေၚ်ပြံၚ်လှာဲဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local extra_case_template, extra_case_template_with_plural
local internal_notes_template
local notes_template
local templates = {}
-- Convert a raw override into a canonicalized list of individual overrides.
-- If input is nil, so is output. Certain junk (e.g. <br/>) is removed,
-- and ~ and ~~ are substituted appropriately; ARGS and CASE are required for
-- this purpose. FORMS is the list of existing case forms and is currently
-- used only to retrieve the dat_sg for handling + in loc/par (this means
-- that any overrides of the dat_sg have to be handled before handling
-- overrides of loc/par). N is the suffix used to retrieve the override --
-- either a number for word-specific overrides, or an empty string for
-- overall overrides.
--
-- It will still be necessary to call m_table_tools.separate_notes() to separate
-- off any trailing "notes" (asterisks, superscript numbers, etc.), and
-- m_links.remove_links() to remove any links to get the raw override form.
canonicalize_override = function(args, case, forms, n)
local val = args[case .. n]
if not val then
return nil
end
-- clean <br /> that's in many multi-form entries and messes up linking
val = rsub(val, "<br%s*/>", "")
-- substitute ~ and ~~ and split by commas
local stem, manualtr
if rfind(case, "_pl") then
stem, manualtr = args.pl, args.pltr
end
if not stem then
stem, manualtr = args.stem, args.stemtr
end
local ustem, umanualtr = com.make_unstressed_once(stem, manualtr)
local stemtr, ustemtr = manualtr, umanualtr
local vals = rsplit(val, "%s*,%s*")
local retvals = {}
for _, val in ipairs(vals) do
local valru, valtr = com.split_russian_tr(val)
valru = rsub(valru, "~~", ustem)
valru = rsub(valru, "~", com.is_stressed(val) and ustem or stem)
if rfind(valru, "^%*") then
valru = rsub(valru, "^%*", "") .. HYPMARKER
end
if valtr then
stemtr = stemtr or com.translit_no_links(stem)
ustemtr = ustemtr or com.translit_no_links(ustem)
valtr = rsub(valtr, "~~", ustemtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and ustemtr or stemtr)
elseif val:find("~") and manualtr then
valtr = com.translit_no_links(val)
valtr = rsub(valtr, "~~", umanualtr)
valtr = rsub(valtr, "~", com.is_stressed(val) and umanualtr or manualtr)
end
if valtr then
if valtr:sub(1, 1) == "*" then
valtr = valtr:sub(2) .. HYPMARKER
end
valtr = com.j_correction(valtr)
end
table.insert(retvals, {valru, valtr})
end
vals = retvals
-- handle + in loc/par meaning "the expected form"; NOTE: This requires
-- that dat_sg has already been processed!
if case == "loc" or case == "par" then
local new_vals = {}
for _, rutr in ipairs(vals) do
-- don't just handle + by itself in case the arg has в or на
-- or whatever attached to it
if rfind(rutr[1], "^%+") or rfind(rutr[1], "[%s%[|]%+") then
for _, dat in ipairs(forms["dat_sg"]) do
local ru, tr = rutr[1], rutr[2]
local datru, dattr = dat[1], dat[2]
local valru, valtr
-- separate off any footnote symbols (which may have been
-- introduced by a *tail or *tailall argument, which we need
-- to process before this stage so overrides don't get
-- automatically marked with footnote symbols); if par,
-- try to preserve them, but with loc this can cause
-- problems in case there are multiple dative forms
-- (stress variants) and the last one is marked with a
-- footnote symbol (occurs in грудь)
local datru_entry, datru_notes = m_table_tools.separate_notes(datru)
local dattr_entry, dattr_notes
if dattr then
dattr_entry, dattr_notes = m_table_tools.separate_notes(dattr)
end
if case == "par" then
valru, valtr = datru_entry, dattr_entry
else
valru, valtr = com.make_ending_stressed(datru_entry, dattr_entry)
datru_notes = ""
dattr_notes = ""
end
-- wrap the word in brackets so it's linked; but not if it
-- appears to already be linked
ru = rsub(ru, "^%+", "[[" .. valru .. "]]")
ru = rsub(ru, "([%[|])%+", "%1" .. valru)
ru = rsub(ru, "(%s)%+", "%1[[" .. valru .. "]]")
ru = ru .. datru_notes
-- do the translit; but it shouldn't have brackets in it
if tr or valtr then
tr = tr or com.translit_no_links(rutr[1])
valtr = valtr or com.translit_no_links(valru)
tr = rsub(tr, "^%+", valtr)
tr = rsub(tr, "(%s)%+", "%1" .. valtr)
tr = tr .. dattr_notes
end
table.insert(new_vals, {ru, tr})
end
else
table.insert(new_vals, rutr)
end
end
vals = new_vals
end
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(vals) do
local ru, tr = v[1], v[2]
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. n .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
vals = newvals
return vals
end
local function process_overrides(args, f, n)
local function process_override(case)
if args[case .. n] then
local overrides = canonicalize_override(args, case, f, n)
if not f[case] then
f[case] = {}
end
local new_overrides = {}
for _, form in ipairs(overrides) do
-- Don't consider overrides of loc/par/voc irregular since
-- they're only specified through overrides; FIXME: Theoretically
-- we could consider loc/par irregular if they don't follow the
-- expected forms; but we'd have to figure out how to eliminate
-- the preposition that may be specified
if not overridable_only_cases_set[case] and
not args.manual and
not contains_rutr_pair(f[case], form) then
local formru, formnotes = m_table_tools.separate_notes(form[1])
if formru ~= "-" then
-- don't mark an override of - as irregular, even if
-- it has an attached footnote symbol
form = com.concat_paired_russian_tr(form, {IRREGMARKER})
end
end
if case == "pauc" then
-- Internal note indicating that the form is for numbers 2, 3 and 4.
form = com.concat_paired_russian_tr(form, {paucal_marker})
end
table.insert(new_overrides, form)
end
f[case] = new_overrides
args.any_overridden[case] = true
end
end
-- do dative singular first because it will be used by loc/par
process_override("dat_sg")
-- now do the rest
for _, case in ipairs(overridable_cases) do
if case ~= "dat_sg" then
process_override(case)
end
end
-- if the nominative is overridden, use it to set the linked version unless
-- that is also specifically overridden
if args["nom_sg" .. n] and not args["nom_sg_linked" .. n] then
f.nom_sg_linked = f.nom_sg
end
if args["nom_pl" .. n] and not args["nom_pl_linked" .. n] then
f.nom_pl_linked = f.nom_pl
end
-- convert empty lists to nil to facilitate computation of accusative
-- case variants below.
for _, case in ipairs(all_cases) do
if f[case] then
if type(f[case]) ~= "table" then
error("Logic error, args[case] should be nil or table")
end
if #f[case] == 0 then
f[case] = nil
end
end
end
end
local function process_tail_args(args, f, n)
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
local function append1(case)
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
append1(case)
if case == "acc_sg" then
append1("acc_sg_in")
append1("acc_sg_an")
elseif case == "acc_pl" then
append1("acc_pl_in")
append1("acc_pl_an")
end
end
local function handle_tail_hyp(suf)
local arg, val
for _, case in ipairs(all_cases) do
arg = args[case .. "_" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args[case .. "_" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
if not rfind(case, "_pl") then
arg = args["sg" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["sg" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
else
arg = args["pl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["pl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
if not rfind(case, "nom_") and not rfind(case, "acc_") then
arg = args["obl" .. suf .. "all" .. n]
if arg then
append_note_all(case, suf == "hyp" and HYPMARKER or arg)
end
arg = args["obl" .. suf .. n]
if arg then
append_note_last(case, suf == "hyp" and HYPMARKER or arg, ">1")
end
end
end
end
handle_tail_hyp("tail")
handle_tail_hyp("hyp")
end
handle_forms_and_overrides = function(args, n, islast)
local f = args.forms
process_tail_args(args, f, n)
process_overrides(args, f, n)
local an = args.thisa
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). This logic duplicates logic in handle_overall_forms_and_overrides();
-- see long comment there. We need to duplicate the whole logic here to
-- handle words like мать-одиночка, which has an override of acc_sg1.
if not args["acc_sg_an" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_an = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_an = f.acc_sg or an == "i" and f.nom_sg or f.gen_sg or f.acc_sg_an
end
end
if not args["acc_sg_in" .. n] then
if args["acc_sg" .. n] then
f.acc_sg_in = f.acc_sg
elseif not args.this_any_non_nil.acc_sg then
f.acc_sg_in = f.acc_sg or an == "a" and f.gen_sg or f.nom_sg or f.acc_sg_in
end
end
if not args["acc_pl_an" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_an = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_an = f.acc_pl or an== "i" and f.nom_pl or f.gen_pl or f.acc_pl_an
end
end
if not args["acc_pl_in" .. n] then
if args["acc_pl" .. n] then
f.acc_pl_in = f.acc_pl
elseif not args.this_any_non_nil.acc_pl then
f.acc_pl_in = f.acc_pl or an == "a" and f.gen_pl or f.nom_pl or f.acc_pl_in
end
end
f.loc = f.loc or f.pre_sg
f.par = f.par or f.gen_sg
f.voc = f.voc or f.nom_sg
-- Set these in case we have plural only, in which case the
-- singular will also get set to these same values in case we are
-- a plural-only word in a singular-only expression.
f.loc_pl = f.loc_pl or f.pre_pl
f.par_pl = f.par_pl or f.gen_pl
f.voc_pl = f.voc_pl or f.nom_pl
f.count = f.count or f.gen_pl
f.pauc = f.pauc or f.gen_sg
local nu = args.thisn
-- If we have a singular-only, set the plural forms to the singular forms,
-- and vice-versa. This is important so that things work in multi-word
-- expressions that combine different number restrictions (e.g.
-- singular-only with singular/plural or singular-only with plural-only,
-- compare "St. Vincent and the Grenadines" [Сент-Винсент и Гренадины]).
if nu == "s" then
f.nom_pl_linked = f.nom_sg_linked
f.nom_pl = f.nom_sg
f.gen_pl = f.gen_sg
f.dat_pl = f.dat_sg
f.acc_pl = f.acc_sg
f.acc_pl_an = f.acc_sg_an
f.acc_pl_in = f.acc_sg_in
f.ins_pl = f.ins_sg
f.pre_pl = f.pre_sg
f.nom_pl = f.nom_sg
f.loc_pl = f.loc
f.par_pl = f.par
f.voc_pl = f.voc
elseif nu == "p" then
f.nom_sg_linked = f.nom_pl_linked
f.nom_sg = f.nom_pl
f.gen_sg = f.gen_pl
f.dat_sg = f.dat_pl
f.acc_sg = f.acc_pl
f.acc_sg_an = f.acc_pl_an
f.acc_sg_in = f.acc_pl_in
f.ins_sg = f.ins_pl
f.pre_sg = f.pre_pl
f.nom_sg = f.nom_pl
f.loc = f.loc_pl
f.par = f.par_pl
f.voc = f.voc_pl
end
end
handle_overall_forms_and_overrides = function(args)
local overall_forms = {}
for _, case in ipairs(displayable_cases) do
overall_forms[case] = concat_word_forms(args.per_word_info, case)
end
local acc_sg_overridden = args.acc_sg
local acc_pl_overridden = args.acc_pl
process_tail_args(args, overall_forms, "")
process_overrides(args, overall_forms, "")
if case_will_be_displayed(args, "pauc") then
insert_if_not(args.internal_notes, paucal_internal_note)
end
-- if IRREGMARKER is anywhere in text, remove all instances and put
-- at the end before any notes.
local function clean_irreg_marker(case, text)
if rfind(text, IRREGMARKER) then
text = rsub(text, IRREGMARKER, "")
local entry, notes = m_table_tools.separate_notes(text)
if case_will_be_displayed(args, case) then
insert_if_not(args.internal_notes, IRREGMARKER .. " Irregular.")
args.any_irreg = true
args.any_irreg_case[case] = true
end
return entry .. IRREGMARKER .. notes
else
return text
end
end
-- set final args[case] and clean up IRREGMARKER.
for _, case in ipairs(all_cases) do
args[case] = overall_forms[case]
if args[case] then
local cleaned_forms = {}
for _, form in ipairs(args[case]) do
local ru, tr = form[1], form[2]
ru = clean_irreg_marker(case, ru)
if tr then
tr = clean_irreg_marker(case, tr)
end
table.insert(cleaned_forms, {ru, tr})
end
args[case] = cleaned_forms
end
end
-- Maybe set the value of the animate/inanimate accusative variants based
-- on nom/acc/gen overrides. Don't do this if there was a specific override
-- of this form. Otherwise, always propagate an accusative singular
-- override, and propagate the nom/gen sg if there wasn't a specific
-- accusative suffix anywhere (occurs in the fem sg and sometimes the neut
-- sg). We need to do this somewhat complicated procedure to get overrides
-- to work correctly, e.g. acc_sg overrides of feminine and neuter nouns
-- (such as мать and полслова) and gen_sg/gen_pl overrides of masculine
-- animate nouns. We also ran into an issue with words like мазло that are
-- neuter-form but can be both masculine animate (in which case the
-- acc sg inherits from the genitive) and neuter animate (in which case the
-- acc sg has the fixed ending -о, same as nominative, despite the animacy).
-- Remember also that the animate/inanimate accusative variants are the ones
-- displayed, not the plain acc_sg/acc_pl ones.
if not args.any_overridden.acc_sg_an then
if acc_sg_overridden then
args.acc_sg_an = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_an = args.acc_sg or args.a == "i" and args.nom_sg or args.gen_sg or args.acc_sg_an
end
end
if not args.any_overridden.acc_sg_in then
if acc_sg_overridden then
args.acc_sg_in = args.acc_sg
elseif not args.any_non_nil.acc_sg then
args.acc_sg_in = args.acc_sg or args.a == "a" and args.gen_sg or args.nom_sg or args.acc_sg_in
end
end
if not args.any_overridden.acc_pl_an then
if acc_pl_overridden then
args.acc_pl_an = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_an = args.acc_pl or args.a == "i" and args.nom_pl or args.gen_pl or args.acc_pl_an
end
end
if not args.any_overridden.acc_pl_in then
if acc_pl_overridden then
args.acc_pl_in = args.acc_pl
elseif not args.any_non_nil.acc_pl then
args.acc_pl_in = args.acc_pl or args.a == "a" and args.gen_pl or args.nom_pl or args.acc_pl_in
end
end
-- Try to set the values of acc_sg and acc_pl. The only time we can't is
-- when the noun is bianimate and the anim/inan values are different.
-- This is used primarily for generate_forms() and generate_multi_forms(),
-- since we don't actually display these forms.
if args.a == "a" then
args.acc_sg = args.acc_sg or args.acc_sg_an
args.acc_pl = args.acc_pl or args.acc_pl_an
elseif args.a == "i" then
args.acc_sg = args.acc_sg or args.acc_sg_in
args.acc_pl = args.acc_pl or args.acc_pl_in
else -- bianimate
args.acc_sg = args.acc_sg or m_table.deepEquals(args.acc_sg_in, args.acc_sg_an) and args.acc_sg_in or nil
args.acc_pl = args.acc_pl or m_table.deepEquals(args.acc_pl_in, args.acc_pl_an) and args.acc_pl_in or nil
end
end
-- Subfunction of concat_word_forms(), used to implement recursively
-- generating all combinations of elements from WORD_FORMS (a list, one
-- element per word, of a list of the forms for a word, each of which is a
-- two-element list of {RUSSIAN, TR}) and TRAILING_FORMS (a list of forms, the
-- accumulated suffixes for trailing words so far in the recursion process,
-- again where each form is a two-element list {RUSSIAN, TR}). Each time we
-- recur we take the last FORMS item off of WORD_FORMS and to each form in
-- FORMS we add all elements in TRAILING_FORMS, passing the newly generated
-- list of items down the next recursion level with the shorter WORD_FORMS.
-- We end up returning a list of concatenated forms, where each list item
-- is a two-element list {RUSSIAN, TR}.
local function concat_word_forms_1(word_forms, trailing_forms)
if #word_forms == 0 then
local retforms = {}
for _, form in ipairs(trailing_forms) do
local ru, tr = form[1], form[2]
-- Remove <insa> and <insb> markers; they've served their purpose.
ru = rsub(ru, "<ins[ab]>", "")
tr = tr and rsub(tr, "<ins[ab]>", "")
table.insert(retforms, {ru, tr})
end
return retforms
else
local last_form_info = table.remove(word_forms)
local last_forms, joiner = last_form_info[1], last_form_info[2]
local new_trailing_forms = {}
for _, form in ipairs(last_forms) do
for _, trailing_form in ipairs(trailing_forms) do
-- If form to prepend is empty, don't add the joiner; this
-- is principally used in overall overrides, where we stuff
-- the entire override into the last word
local full_form = form[1] == "" and trailing_form or
com.concat_paired_russian_tr(form,
com.concat_paired_russian_tr(joiner, trailing_form),
"movenotes")
if rfind(full_form[1], "<insa>") and rfind(full_form[1], "<insb>") then
-- REJECT! So we don't get mixtures of the two feminine
-- instrumental singular endings.
else
table.insert(new_trailing_forms, full_form)
end
end
end
return concat_word_forms_1(word_forms, new_trailing_forms)
end
end
-- Generate a list of overall forms by concatenating the per-word forms.
-- PER_WORD_INFO comes from args.per_word_info and is a list of
-- WORD_INFO items, one per word, each of which a two element list of
-- WORD_FORMS (a table listing the forms for each case) and JOINER (a string).
-- We loop over all possible combinations of elements from each word's list
-- of forms for the given case; this requires recursion.
concat_word_forms = function(per_word_info, case)
local word_forms = {}
-- Gather the appropriate word forms. We have to recreate this anew
-- because it will be destructively modified by concat_word_forms_1().
for _, word_info in ipairs(per_word_info) do
table.insert(word_forms, {word_info[1][case], word_info[2]})
end
-- We need to start the recursion with the second parameter containing
-- one blank element rather than no elements, otherwise no elements
-- will be propagated to the next recursion level.
return concat_word_forms_1(word_forms, {{""}})
end
local accel_forms = {
nom_sg = "nom|s",
nom_sg_linked = "nom|s",
nom_pl = "nom|p",
nom_pl_linked = "nom|p",
gen_sg = "gen|s",
gen_pl = "gen|p",
dat_sg = "dat|s",
dat_pl = "dat|p",
acc_sg_an = "an|acc|s",
acc_pl_an = "an|acc|p",
acc_sg_in = "in|acc|s",
acc_pl_in = "in|acc|p",
ins_sg = "ins|s",
ins_pl = "ins|p",
pre_sg = "pre|s",
pre_pl = "pre|p",
loc = "loc|s",
loc_pl = "loc|p",
voc = "voc|s",
voc_pl = "voc|p",
par = "par|s",
par_pl = "par|p",
count = "count form",
pauc = "pau",
}
-- Make the table
make_table = function(args)
local data = {}
data.after_title = " " .. args.heading
data.number = args.nonumber and "" or numbers[args.n]
local lemma_forms = args[args.n == "p" and "nom_pl" or "nom_sg"]
data.lemma = nom.show_form(args.explicit_lemma and {{args.explicit_lemma, args.explicit_lemmatr}} or
args[args.n == "p" and "nom_pl_linked" or "nom_sg_linked"], "lemma", nil, nil)
data.title = args.title or format(args.old and old_title_temp or title_temp, data)
local sg_an_in_equal = m_table.deepEquals(args.acc_sg_an, args.acc_sg_in)
local pl_an_in_equal = m_table.deepEquals(args.acc_pl_an, args.acc_pl_in)
for _, case in ipairs(displayable_cases) do
local accel_form = accel_forms[case]
if not accel_form then
error("Something wrong, can't find accelerator form for " .. case)
end
if (sg_an_in_equal and (case == "acc_sg_an" or case == "acc_sg_in") or
pl_an_in_equal and (case == "acc_pl_an" or case == "acc_pl_in")) then
accel_form = rsub(accel_form, "^[ai]n|", "")
end
if args.n == "p" then
accel_form = rsub(accel_form, "|p$", "")
end
data[case] = nom.show_form(args[case], false, accel_form, lemma_forms, "remove monosyllabic accents only lemma")
end
local temp = nil
if args.n == "s" then
data.nom_x = data.nom_sg
data.gen_x = data.gen_sg
data.dat_x = data.dat_sg
data.acc_x_an = data.acc_sg_an
data.acc_x_in = data.acc_sg_in
data.ins_x = data.ins_sg
data.pre_x = data.pre_sg
if sg_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
elseif args.n == "p" then
data.nom_x = data.nom_pl
data.gen_x = data.gen_pl
data.dat_x = data.dat_pl
data.acc_x_an = data.acc_pl_an
data.acc_x_in = data.acc_pl_in
data.ins_x = data.ins_pl
data.pre_x = data.pre_pl
data.par = data.par_pl
data.loc = data.loc_pl
data.voc = data.voc_pl
if pl_an_in_equal then
temp = "one_number"
else
temp = "one_number_split_animacy"
end
else
if pl_an_in_equal then
temp = "both_numbers"
elseif sg_an_in_equal then
temp = "both_numbers_split_animacy_plural_only"
else
temp = "both_numbers_split_animacy"
end
end
for _, extra_case in ipairs({
{"par", "partitive"},
{"loc", "locative"},
{"voc", "vocative"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "s" and args.n ~= "p" and args.any_overridden[case .. "_pl"] then
if not args.any_overridden[case] then
data[case] = ""
end
template = extra_case_template_with_plural
elseif args.n ~= "p" and args.any_overridden[case] or args.n == "p" and args.any_overridden[case .. "_pl"] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
for _, extra_case in ipairs({
{"count", "count form"},
{"pauc", "paucal"},
}) do
local case, engcase, template = unpack(extra_case)
local a = args.a
local colspan = (a == "b" or a == "bi" or a == "both" or a == "ai" or a == "ia") and 2 or 1
if args.n ~= "p" and args.any_overridden[case] then
template = extra_case_template
end
if template then
template = format(template(colspan), {case=case, engcase=engcase})
data[case .. "_clause"] = format(template, data)
else
data[case .. "_clause"] = ""
end
end
local notes = get_arg_chain(args, "notes", "notes")
local all_notes = {}
for _, note in ipairs(args.internal_notes) do
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
for _, note in ipairs(notes) do
-- Here too.
local symbol, entry = m_table_tools.get_initial_notes(note)
table.insert(all_notes, symbol .. entry)
end
data.notes = table.concat(all_notes, "<br />")
data.notes_clause = data.notes ~= "" and format(notes_template, data) or ""
return format(templates[temp], data)
end
function extra_case_template(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
|
|-]===]):format(colspan)
end
function extra_case_template_with_plural(colspan)
colspan = colspan or 1
return ([===[
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=%s | {engcase}
| {\op}{case}{\cl}
| {\op}{case}_pl{\cl}
|-]===]):format(colspan)
end
notes_template = [===[
<div style="width:100%;text-align:left;background:var(--wikt-palette-lightblue, #d9ebff);">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame" data-toggle-category="လဟုတ်စှ်ေ" style="max-width:MINWIDTHem">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);">{title}<span style="font-weight:normal;">{after_title}</span> </div>
<div class="NavContent">
{\op}| style="table-layout:fixed; text-align:center; max-width:MINWIDTHem; width:100%;" class="inflection inflection-table"
|- class="rowgroup"
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[|-{par_clause}{loc_clause}{voc_clause}{count_clause}{pauc_clause}
|{\cl}{notes_clause}</div></div></div>]===]
end
templates["both_numbers"] = template_prelude("45") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_sg_in}
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["both_numbers_split_animacy_plural_only"] = template_prelude("50") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဨကဝုစ်
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | ကိုန်ဗဟုဝစ်
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_sg}
| data-accel-col=2 | {nom_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_sg}
| data-accel-col=2 | {gen_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_sg}
| data-accel-col=2 | {dat_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| data-accel-col=1 rowspan=2 | {acc_sg_an}
| data-accel-col=2 | {acc_pl_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=2 | {acc_pl_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_sg}
| data-accel-col=2 | {ins_pl}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_sg}
| data-accel-col=2 | {pre_pl}
]===] .. template_postlude()
templates["one_number"] = template_prelude("30") .. [===[
! style="width:7em;background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ကမ္မကာရက
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
templates["one_number_split_animacy"] = template_prelude("35") .. [===[
! style="width:15em;background:var(--wikt-palette-lightblue, #d9ebff);" colspan=2 |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {number}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | မဒုၚ်ယၟု
| {nom_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဗဳဇဂကူ
| {gen_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ပြကမ္မကာရက
| {dat_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | လမျီုလုပ်ကၠုၚ်
| {acc_x_an}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | မသက္ကုဟၟဲကဵုလမျီု
| {acc_x_in}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {ins_x}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| {pre_x}
]===] .. template_postlude()
return export
248dedkqdgoape1d1se73eygjl8isjf
မဝ်ဂျူ:ru-adjective
828
25170
399862
133606
2026-07-23T00:46:11Z
咽頭べさ
33
399862
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
adjectives.
Author: Benwing, rewritten from early version by Wikitiki89
Arguments:
1: lemma; nom sg, or just the stem if an explicit declension type is
given in arg 2
2: declension type (usually omitted to autodetect based on the lemma),
along with any short accent type and optional irregular short stem;
see below.
CASE_NUMGEN: Override a given form; see abbreviations below
suffix: any suffix to attach unchanged to the end of each form
notes: Notes to add to the end of the table
title: Override the title
shorttail: Footnote (e.g. *, 1, 2, etc.) to add to short forms if
there's more than one; automatically superscripted
shorttailall: Same as shorttail= but applies to all short forms even
if there's only one
CASE_NUMGEN_tail: Like shorttailall but only for a specific form
nofull: Short forms only
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
short: short form
Number/gender abbreviations:
m: masculine singular
n: neuter singular
f: feminine singular
p: plural
mp: masculine plural (old-style and special numeral tables only)
fp: masculine plural (special numeral tables only)
Animacy abbreviations:
an: animate
in: inanimate
Declension-type argument (arg 2):
Form is DECLSPEC or DECLSPEC,DECLSPEC,... where DECLSPEC is
one of the following:
DECLTYPE:SHORTACCENT:SHORTSTEM
DECLTYPE:SHORTACCENT
DECLTYPE
SHORTACCENT:SHORTSTEM
SHORTACCENT
(blank)
DECLTYPE should normally be omitted, and the declension autodetected
from the ending; or it should be ь, to indicate that an adjective
in -ий is of the possessive variety with an extra -ь- in most of
the endings. Alternatively, it can be an explicit declension type,
in which case the lemma field needs to be replaced with the bare
stem; the following are the possibilities:
ый ий ой ьий short mixed manual (new-style)
ый ій ьій short stressed-short mixed proper stressed-proper
ъ-short ъ-stressed-short ъ-mixed ъ-proper ъ-stressed-proper
manual (old-style, where ъ-* is a synonym for *, for any *)
SHORTACCENT is one of a a' b b' c c' c'' to auto-generate the
short forms with the specified accent pattern (following
Zaliznyak); if omitted, no short forms will be auto-generated.
SHORTACCENT can contain a * in it for "reducible" adjectives,
where the short masculine singular has an epenthetic vowel
in the final syllable. It can also contain (1) or (2) to
indicate special cases. Both are used in conjunction with
adjectives in -нный/-нний. Special case (1) causes the
short masculine singular to end in -н instead of -нн; special
case (2) causes all short forms to end this way.
SHORTSTEM, if present, is used as the short stem to base the
short forms off of, instead of the normal adjective long stem
(possibly with a final-syllable accent added in the case of
declension type -о́й).
TODO:
1. Figure out what the symbol X-inside-square (⊠) means, which seems to go with
all adjectives in -о́й with multi-syllabic stems. It may mean that the
masculine singular short form is missing. If this indeed a regular thing,
we need to implement it (and if it's regular but means something else,
we need to implement that, too). Also figure out what the other signs
on pages 68-76 etc. mean: -, X, ~, П₂, Р₂, diamond (♢), triangle (△; might
simply mean a misc. irregularity; explained on p. 61).
2. Mark irregular overridden forms with △ (esp. appropriate for short forms).
3. Should non-reducible adjectives in -нный and -нний default to special case
(1)?
4. In the case of a non-dereducible short masc sing of stress type b, we don't
currently move the stress to the last syllable. Should we?
5. FIXME: In decline(), we used to default acc_n to nom_n. Now we do that in
handle_forms_and_overrides(). Verify that this is more correct.
6. FIXME: Allow multiple heads, both to handle cases where two manual translits
exist (or rather, one automatic and one manual), and cases where two
stresses are possible, e.g. мину́вший or ми́нувший.
7. FIXME: Add code to generate the regular comparative. The rules are as
follows: If the stem doesn't end in к г х, add -ee with no stress change
if the short form is type a, else add -е́е (including type a'). If the stem
ends in к г х, turn the last consonant into ч ж ш, add -е, and place the
stress on the syllable preceding the ending. (E.g. дорого́й -> доро́же)
]=]--
local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_table = require("Module:table")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local strutils = require("Module:string utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
----------------------------- Utility functions ------------------------
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local usub = mw.ustring.sub
-- 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
-- Insert a single form (consisting of {RUSSIAN, TR}) or a list of such
-- forms into an existing list of such forms, adding NOTESYM (a string or nil)
-- to the new forms if not nil. Return whether an insertion was performed.
local function insert_forms_into_existing_forms(existing, newforms, notesym)
if type(newforms) ~= "table" then
newforms = {newforms}
end
local inserted = false
for _, item in ipairs(newforms) do
if not m_table.contains(existing, item) then
if notesym then
item = com.concat_paired_russian_tr(item, {notesym})
end
table.insert(existing, item)
inserted = true
end
end
return inserted
end
local function track(page)
m_debug.track("ru-adjective/" .. page)
return true
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-------------------- Global declension/case/etc. variables -------------------
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
local declensions = {}
local declensions_old = {}
local internal_notes_table = {}
local internal_notes_table_old = {}
local internal_notes_genders = {}
local internal_notes_genders_old = {}
local short_declensions = {}
local short_declensions_old = {}
-- Formerly used for the ой-rare type, which has been removed; but keep
-- the code around in case we need it later.
local short_internal_notes_table = {}
local short_internal_notes_table_old = {}
local short_stress_patterns = {}
local long_cases = {
"nom_m", "nom_n", "nom_f", "nom_p",
"gen_m", "gen_f", "gen_p",
"dat_m", "dat_f", "dat_p",
"acc_m_an", "acc_m_in", "acc_p_an", "acc_p_in", "acc_f", "acc_n",
"ins_m", "ins_f", "ins_p",
"pre_m", "pre_f", "pre_p",
-- extra old long cases
"nom_mp",
"acc_mp_an", "acc_mp_in",
-- extra dva cases
"nom_fp",
"acc_fp_an", "acc_fp_in",
-- extra oba cases
"gen_mp", "gen_fp",
"dat_mp", "dat_fp",
"ins_mp", "ins_fp",
"pre_mp", "pre_fp",
-- extra cases for compounds of два
"acc_mp", "acc_fp",
}
-- Short cases and corresponding numbered arguments
local short_cases = {
"short_m", "short_n", "short_f", "short_p"
}
-- Create master list of all possible cases (actually case/number/gender pairs)
local all_cases = mw.clone(long_cases)
for _, case in ipairs(short_cases) do
m_table.insertIfNot(all_cases, case)
end
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same.
local test_new_ru_adjective_module = false
-- Forward references to functions
local tracking_code
local categorize
local detect_stem_and_accent_type
local construct_bare_and_short_stem
local decline
local canonicalize_override
local handle_forms_and_overrides
local decline_short
local make_table
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Implementation of main entry point
function export.do_generate_forms(args, old, manual)
local orig_args
if test_new_ru_adjective_module then
orig_args = mw.clone(args)
end
if args[3] or args[4] or args[5] or args[6] then
error("Numbered short forms no longer supported")
end
if args.shorttailall then
track("shorttailall")
end
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
args.forms = {}
args.categories = {}
old = old or args.old
args.old = old
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
args.internal_notes = {}
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
if args.notes then
local notes, entry = m_table_tools.get_initial_notes(args.notes)
args.notes = notes .. entry
end
local overall_short_forms_allowed
manual = manual or args[2] == "manual"
args.manual = manual
local decl_types = manual and "$" or args[2] or ""
local lemmas = manual and "-" or args[1] or SUBPAGENAME
local normal_short_classes, rare_short_classes, dated_short_classes
local saw_no_short
for _, lemma_and_tr in ipairs(rsplit(lemmas, ",")) do
-- reset these for each lemma so we get the short classes of the last
-- lemma (doesn't really matter, as they should be the same for all
-- lemmas)
normal_short_classes = {}
rare_short_classes = {}
dated_short_classes = {}
saw_no_short = false
for _, decl_type in ipairs(rsplit(decl_types, ",")) do
local lemma, lemmatr = com.split_russian_tr(lemma_and_tr)
-- if lemma ends with -ся, strip it and act as if suffix=ся given
-- (or rather, prepend ся to suffix)
local active_base = rmatch(lemma, "^(.*)ся$")
if active_base then
lemma = active_base
lemmatr = com.strip_tr_ending(lemmatr, "ся")
args.refl = true
args.real_suffix = com.concat_paired_russian_tr({"ся"}, args.suffix)
else
args.refl = false
args.real_suffix = args.suffix
end
-- Auto-detect actual decl type, and get short accent and overriding
-- short stem, if specified.
local stem, stemtr, short_accent, short_stem, short_stemtr, datedrare
stem, stemtr, decl_type, short_accent, short_stem, datedrare =
detect_stem_and_accent_type(lemma, lemmatr, decl_type, args)
if rfind(decl_type, "^[іи]й$") and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl_type = "ый"
end
if datedrare == "none" then
saw_no_short = true
end
local proper_decl = m_table.contains({"proper", "stressed-proper"}, decl_type)
-- Use args.real_surname to avoid overwriting args.surname, since we may be overwriting
-- `args` multiple times. FIXME: Use a separate data structure for this.
args.real_surname = proper_decl or args.surname
local short_title
if short_accent then
short_title = short_accent
elseif args.real_surname then
short_title = "surname"
elseif m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed"}, decl_type) then
short_title = "possessive"
end
if short_title then
if datedrare == "dated" then
m_table.insertIfNot(dated_short_classes, short_title)
elseif datedrare == "rare" then
m_table.insertIfNot(rare_short_classes, short_title)
else
m_table.insertIfNot(normal_short_classes, short_title)
end
end
if short_stem then
short_stem, short_stemtr = com.split_russian_tr(short_stem)
end
stem, args.allow_unaccented = rsubb(stem, "^%*", "")
if args.allow_unaccented then
track("allow-unaccented")
end
-- Treat suffixes without an accent, and suffixes with an accent on
-- the initial hyphen, as if they were preceded with a *, which
-- overrides all the logic that normally (a) normalizes the accent,
-- and (b) complains about multisyllabic words without an accent.
-- Don't do this if lemma is just -, which is used specially in
-- manual declension tables.
if lemma ~= "-" and (rfind(lemma, "^%-́") or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
if not args.allow_unaccented and com.needs_accents(lemma) then
-- Technically we don't need accents in -ой adjectives (which are
-- always ending-stressed) and in -ый adjectives with a monosyllabic
-- stem, such as полный (which are always stem-stressed), but it's
-- better to enforce accents in all multisyllabic words, for
-- consistency with nouns and verbs. Note that we still don't
-- require an accent in monosyllabic adjectives such as злой.
error("Lemma must have an accent in it: " .. lemma)
end
-- Set stem and unstressed version. Also construct end-accented version
-- of stem if unstressed; needed for short forms of adjectives of
-- type -о́й. We do this here before doing the dereduction
-- transformation so that we don't end up stressing an unstressed
-- epenthetic vowel, and so that the previous syllable instead ends
-- up stressed (in type -о́й adjectives the stem won't have any stress).
-- Note that the closest equivalent in nouns is handled in
-- attach_unstressed(), which puts the stress onto the final syllable
-- if the stress pattern calls for ending stress in the genitive
-- plural. This works there because
-- (1) It won't stress an unstressed epenthetic vowel because the
-- cases where the epenthetic vowel is unstressed are precisely
-- those with stem stress in the gen pl, not ending stress;
-- (2) There isn't a need to stress the syllable preceding an
-- unstressed epenthetic vowel because that syllable should
-- already have stress, since we require that the base stem form
-- (parameter 2) have stress in it whenever any case form has
-- stem stress. This isn't the case here in type -о́й adjectives.
-- NOTE: FIXME: I can't actually quote any forms from Zaliznyak
-- (at least not from pages 58-60, where this is discussed) that
-- seem to require last-stem-syllable-stress, i.e. where the stem is
-- multisyllabic. The two examples given are both unusual: дорого́й
-- has stress on the initial syllable до́рог etc. and these forms are
-- marked with a triangle (indicating an apparent irregularity); and
-- голубо́й seems not to have a masculine singular short form, and it's
-- accent pattern b, so the remaining forms are all ending-stressed.
-- In fact it's possible that these examples don't exist: It appears
-- that all the multisyllabic adjectives in -о́й listed in the
-- dictionary have a marking next to them consisting of an X inside of
-- a square, which is glossed p. 69 to something I don't understand,
-- but may be saying that the masculine singular short form is
-- missing. If this is regular, we need to implement it.
args.stem, args.stemtr = stem, stemtr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, stemtr)
local accented_stem, accented_stemtr = stem, stemtr
if not args.allow_unaccented then
if accented_stemtr and com.is_unstressed(accented_stem) ~= com.is_unstressed(accented_stemtr) then
error("Stem " .. accented_stem .. " and translit " .. accented_stemtr .. " must have same accent pattern")
end
if com.is_unstressed(accented_stem) then
accented_stem, accented_stemtr =
com.make_ending_stressed(accented_stem, accented_stemtr)
end
end
local short_forms_allowed = manual and true or decl_type == "ый" or
decl_type == "ой" or decl_type == (old and "ій" or "ий")
overall_short_forms_allowed = overall_short_forms_allowed or
short_forms_allowed
if not short_forms_allowed then
-- FIXME: We might want to allow this in case we have a
-- reducible short, mixed or proper possessive adjective. But
-- in that case we need to reduce rather than dereduce to get
-- the stem.
if short_accent or short_stem then
error("Cannot specify short accent or short stem with declension type " .. decl_type .. ", as short forms aren't allowed")
end
if args.short_m or args.short_f or args.short_n or args.short_p then
error("Cannot specify explicit short forms with declension type " .. decl_type .. ", as short forms aren't allowed")
end
end
local orig_short_accent = short_accent
local short_decl_type
short_accent, short_decl_type = construct_bare_and_short_stem(args,
short_accent, short_stem, short_stemtr, accented_stem,
accented_stemtr, old, decl_type)
local decls = old and declensions_old or declensions
local short_decls = old and short_declensions_old or short_declensions
if not decls[decl_type] then
error("Unrecognized declension type " .. decl_type)
end
if short_accent == "" then
error("Short accent type cannot be blank, should be omitted or given")
end
if short_accent and not short_stress_patterns[short_accent] then
error("Unrecognized short accent type " .. short_accent)
end
tracking_code(decl_type, args, orig_short_accent, short_accent,
short_stem, datedrare, short_forms_allowed)
if not manual and enable_categories then
categorize(decl_type, args, orig_short_accent, short_accent,
short_stem)
end
decline(args, decls[decl_type], m_table.contains({"ой", "ьей", "й-short", "stressed-short", "stressed-proper"}, decl_type))
if short_forms_allowed and short_accent then
decline_short(args, short_decls[short_decl_type],
short_stress_patterns[short_accent], datedrare)
end
local intable = old and internal_notes_table_old or internal_notes_table
local shortintab = old and short_internal_notes_table_old or
short_internal_notes_table
local internal_note = intable[decl_type] or shortintab[short_decl_type]
if internal_note then
m_table.insertIfNot(args.internal_notes, internal_note)
end
end
end
local short_class_titles = {}
local function make_short_class_title(short_classes, datedrare)
local sct = table.concat(short_classes, ",") -- short class title
if sct == "" then
return
end
if not m_table.contains({"surname", "possessive"}, sct) then
-- Convert e.g. a*,a(1) into a*[(1)], either finally or followed by
-- comma.
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%))$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%)),", "%1*[%2],")
-- Same for a(1),a*.
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*,", "%1*[%2],")
-- Convert (1), (2) to ①, ②.
sct = rsub(sct, "%(1%)", "①")
sct = rsub(sct, "%(2%)", "②")
-- Add a * before ①, ②, consistent with Zaliznyak.
sct = rsub(sct, "([abc]'*)([①②])", "%1*%2")
-- Convert ' and '' to ʹ and ʺ, consistent with Zaliznyak.
sct = sct:gsub("''", "ʺ"):gsub("'", "ʹ")
if args.nofull then
sct = "short-form-only class " .. sct
else
sct = "short class " .. sct
end
end
if datedrare then
sct = datedrare .. " " .. sct
end
table.insert(short_class_titles, sct)
end
make_short_class_title(normal_short_classes, nil)
make_short_class_title(rare_short_classes, "rare")
make_short_class_title(dated_short_classes, "dated")
if #short_class_titles == 0 then
if saw_no_short then
args.short_class_title = "no short forms"
else
args.short_class_title = "unknown short forms"
end
else
args.short_class_title = table.concat(short_class_titles, " / ")
end
handle_forms_and_overrides(args, overall_short_forms_allowed)
-- Test code to compare existing module to new one.
if test_new_ru_adjective_module then
local m_new_ru_adjective = require("Module:User:Benwing2/ru-adjective")
local newargs = m_new_ru_adjective.do_generate_forms(orig_args, old, manual)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
if not m_table.deepEquals(arg, newarg) then
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
if not difdecl then
track("same-decl")
end
end
return args
end
local function process_params(frame, include_form)
local boolean = {type = "boolean"}
local params = {
[1] = true,
[2] = true,
suffix = true,
title = true,
special = true,
shorttail = true,
shorttailall = true,
notes = true,
old = boolean,
noneuter = boolean,
nofull = boolean,
surname = boolean,
pronoun = boolean
}
if include_form then
params.form = {required = true}
end
for _, case in ipairs(all_cases) do
params[case] = true
params[case .. "_tail"] = true
params[case .. "_tailall"] = true
end
return require("Module:parameters").process(frame:getParent().args, params)
end
-- Implementation of main entry point
local function do_show(frame, old, manual)
local args = export.do_generate_forms(process_params(frame), old, manual)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- The main entry point for manual declension tables.
function export.show_manual(frame)
return do_show(frame, false, "manual")
end
-- The main entry point for manual old declension tables.
function export.show_manual_old(frame)
return do_show(frame, true, "manual")
end
-- Entry point for use in Module:ru-noun.
function export.get_nominal_decl(decl, gender, old)
local d = old and declensions_old[decl] or declensions[decl]
local n = {}
if gender == "m" then
n.nom_sg = d.nom_m
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
elseif gender == "f" then
n.nom_sg = d.nom_f
n.gen_sg = d.gen_f
n.dat_sg = d.dat_f
n.acc_sg = d.acc_f
n.ins_sg = d.ins_f
n.pre_sg = d.pre_f
elseif gender == "n" then
n.nom_sg = d.nom_n
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.acc_sg = d.acc_n
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
else
assert(false, "Unrecognized gender: " .. gender)
end
n.nom_pl = d.nom_p
n.gen_pl = d.gen_p
n.dat_pl = d.dat_p
n.ins_pl = d.ins_p
n.pre_pl = d.pre_p
if gender == "m" and d.nom_mp then
n.nom_pl = d.nom_mp
end
local intable = old and internal_notes_table_old or internal_notes_table
local ingenders = old and internal_notes_genders_old or internal_notes_genders
-- FIXME, what if there are multiple internal notes? See comment in
-- do_generate_forms().
local internal_notes = ingenders[decl] and m_table.contains(ingenders[decl], gender) and intable[decl]
return n, internal_notes
end
local function get_form(forms)
local canon_forms = {}
for _, form in ipairs(forms) do
local ru, tr = form[1], form[2]
local ruentry = m_table_tools.get_notes(ru)
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.get_notes(tr)
end
ruentry = m_links.remove_links(ruentry)
m_table.insertIfNot(canon_forms, {ruentry, trentry})
end
return com.concat_forms(canon_forms)
end
-- The entry point for 'ru-adj-forms' to generate all adjective forms.
function export.generate_forms(frame)
local args = export.do_generate_forms(process_params(frame), false)
local ins_text = {}
for _, case in ipairs(all_cases) do
if args[case] then
table.insert(ins_text, case .. "=" .. get_form(args[case]))
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-adj-form' to generate a particular adjective form.
function export.generate_form(frame)
local args = process_params(frame, "include form")
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
tracking_code = function(decl_class, args, orig_short_accent, short_accent,
short_stem, datedrare)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
local function dotrack(prefix)
if prefix ~= "" then
track(prefix)
prefix = prefix .. "/"
end
track(prefix .. decl_class)
for _, hint_type in ipairs(hint_types) do
track(prefix .. hint_type)
track(prefix .. decl_class .. "/" .. hint_type)
end
end
dotrack("")
if args.short_m or args.short_f or args.short_n or args.short_p then
dotrack("short")
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
dotrack("reducible")
dotrack("reducible/" .. short_accent)
end
if rfind(orig_short_accent, "%(1%)") then
dotrack("special-case-1")
dotrack("special-case-1/" .. short_accent)
end
if rfind(orig_short_accent, "%(2%)") then
dotrack("special-case-2")
dotrack("special-case-2/" .. short_accent)
end
end
if short_accent then
dotrack("short-accent/" .. short_accent)
if datedrare == "dated" then
dotrack("short-accent-dated")
dotrack("short-accent-dated/" .. short_accent)
elseif datedrare == "rare" then
dotrack("short-accent-rare")
dotrack("short-accent-rare/" .. short_accent)
end
elseif datedrare == "none" then
dotrack("short-accent/none")
else
dotrack("short-accent/unknown")
end
if short_stem then
dotrack("explicit-short-stem")
dotrack("explicit-short-stem/" .. short_accent)
end
for _, case in ipairs(all_cases) do
if args[case] then
track("irreg/" .. case)
-- questionable use: dotrack("irreg/" .. case)
end
end
end
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the part of speech.
local function insert_category(categories, cat, plpos)
-- table.insert(categories, "Russian " .. rsub(cat, "~", plpos))
end
categorize = function(decl_type, args, orig_short_accent, short_accent,
short_stem)
local plpos = args.real_surname and "surnames" or args.pronoun and "pronouns" or "adjectives"
-- Insert category CAT into the list of categories in ARGS.
local function insert_cat(cat)
-- insert_category(args.categories, cat, plpos)
end
-- FIXME: For compatibility with old {{temp|ru-adj7}}, {{temp|ru-adj8}},
-- {{temp|ru-adj9}}; maybe there's a better way.
if m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed",
"proper", "stressed-proper"}, decl_type) then
-- insert_cat("possessive ~")
end
if not args.pronoun then
if m_table.contains({"ьій", "ьий", "ьей"}, decl_type) then
-- insert_cat("long possessive ~")
elseif m_table.contains({"short", "stressed-short", "й-short"}, decl_type) then
-- insert_cat("short possessive ~")
elseif m_table.contains({"mixed"}, decl_type) then
-- insert_cat("mixed possessive ~")
elseif m_table.contains({"proper", "stressed-proper"}, decl_type) then
-- Don't insert a category like [[:Category:Russian proper-name surnames]]. Instead, rely on
-- [[:Category:Russian possessive surnames]] generated above.
if not args.real_surname then
-- insert_cat("proper-name ~")
end
elseif decl_type == "$" then
-- insert_cat("indeclinable ~")
else
local hint_types = com.get_stem_trailing_letter_type(args.stem)
-- insert English version of Zaliznyak stem type
local stem_type =
m_table.contains(hint_types, "velar") and "velar-stem" or
m_table.contains(hint_types, "sibilant") and "sibilant-stem" or
m_table.contains(hint_types, "c") and "ц-stem" or
m_table.contains(hint_types, "i") and "i-stem" or
m_table.contains(hint_types, "vowel") and "vowel-stem" or
m_table.contains(hint_types, "soft-cons") and "vowel-stem" or
m_table.contains(hint_types, "palatal") and "vowel-stem" or
decl_type == "ий" and "soft-stem" or
"hard-stem"
if stem_type == "soft-stem" or stem_type == "vowel-stem" then
-- insert_cat(stem_type .. " ~")
else
-- insert_cat(stem_type .. " " .. (m_table.contains({"ой", "ьей", "й-short"}, decl_type) and "ending-stressed" or "stem-stressed") .. " ~")
end
end
if m_table.contains({"ой", "ьей", "й-short"}, decl_type) then
-- insert_cat("ending-stressed ~")
end
end
local short_forms_allowed = m_table.contains({"ый", "ой", "ій", "ий"}, decl_type)
if short_forms_allowed then
local override_m = args.short_m
local override_f = args.short_f
local override_n = args.short_n
local override_p = args.short_p
local has_short = short_accent or override_m or override_f or
override_n or override_p
local missing_short = override_m == "-" or
override_f == "-" or override_n == "-" or override_p == "-" or
not short_accent and (not override_m or not override_f or
not override_n or not override_p)
if has_short then
insert_cat("~ with short forms")
if missing_short then
-- insert_cat("~ with missing short forms")
end
end
if short_accent then
-- insert_cat("~ with short accent pattern " .. (short_accent:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
-- insert_cat("~ with reducible short stem")
end
if rfind(orig_short_accent, "%(1%)") then
-- insert_cat("~ with Zaliznyak short form special case 1")
end
if rfind(orig_short_accent, "%(2%)") then
-- insert_cat("~ with Zaliznyak short form special case 2")
end
end
if short_stem and short_stem ~= args.stem then
insert_cat("~ with irregular short stem")
end
end
for _, case in ipairs(all_cases) do
if args[case] and args[case] ~= "-" then
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
short="short",
})
engcase = rsub(engcase, "(_[a-z]*)$", {
_m=" masculine singular", _f=" feminine singular",
_n=" neuter singular", _p=" plural",
_mp=" masculine plural"
})
-- insert_cat("~ with irregular " .. engcase)
end
end
if args.nofull then
-- insert_cat("short-form-only ~")
end
end
--------------------------------------------------------------------------
-- Autodetection and stem munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the base and the ending; also extract the accent type for short
-- adjectives and optional short stem. DECL is the value passed in, and
-- might already specify the ending. Return five values: STEM, STEMTR, DECL,
-- SHORT_ACCENT (accent class of short adjective, or nil for no short
-- adjectives other than specified through overrides), SHORT_STEM (special
-- stem of short adjective, nil if same as long stem). The return value of
-- SHORT_STEM is taken directly from the argument and will include any
-- manual translit.
detect_stem_and_accent_type = function(lemma, tr, decl, args)
local datedrare = false
-- If it looks like a short decl type, canonicalize. [abc] for types
-- a, b, c'', etc.; [d] for dated-*; [r] for rare-*;
-- [-] for - (no short forms); [*(] for * and (1) and (2) modifiers,
-- which might precede the letter.
if rfind(decl, "^[abcdr*(-]") then
decl = ":" .. decl
end
local splitvals = rsplit(decl, ":")
if #splitvals > 3 then
error("Should be at most three colon-separated parts of a declension spec: " .. decl)
end
local short_accent, short_stem
decl, short_accent, short_stem = splitvals[1], splitvals[2], splitvals[3]
-- Check for dated variant of short accent
local dated_short = short_accent and rmatch(short_accent, "^dated%-(.*)$")
if dated_short then
datedrare = "dated"
short_accent = dated_short
else
-- Check for rare variant of short accent
local rare_short = short_accent and rmatch(short_accent, "^rare%-(.*)$")
if rare_short then
datedrare = "rare"
short_accent = rare_short
end
end
decl = ine(decl)
-- Resolve aliases
if decl then
decl = rsub(decl, "^ъ%-", "")
end
if short_accent == "-" then
short_accent = nil
datedrare = "none"
end
short_accent = ine(short_accent)
short_stem = ine(short_stem)
if short_stem and not short_accent then
error("With explicit short stem " .. short_stem .. ", must specify short accent")
end
local base, ending
-- The while loop appears to function solely as a way of allowing a
-- jump to the end of the loop with a 'break' statement. I don't think
-- the loop is ever run more than once.
while true do
if not decl or decl == "ь" then
base, ending = rmatch(lemma, "^(.*)([ыиіое]́?й)$")
if base then
if ending == "ий" and decl == "ь" then
ending = "ьий"
elseif ending == "ій" and decl == "ь" then
ending = "ьій"
elseif ending == "е́й" or (ending == "ей" and com.is_monosyllabic(lemma)) then
ending = "ье́й"
end
tr = com.strip_tr_ending(tr, ending)
-- -ий/-ій will be converted to -ый after velars and sibilants
-- by the caller
decl = com.make_unstressed(ending)
break
else
-- It appears that short, mixed and proper adjectives are always
-- either of the -ов/ев/ёв or -ин/ын types. The former type is
-- always (or almost always?) short, while the latter can be
-- either; apparently mixed is the more "modern" type of
-- declension, and short is "older". However, both -ов/ев/ёв or
-- -ин/ын are of type "proper" (similar to "short") when
-- capitalized.
--
-- NOTE: Following regexp is accented
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]́н)ъ?$")
if base then
decl = "stressed-proper"
break
end
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[еёо]́?в)ъ?$")
if not base then
-- Following regexp is not stressed
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]н)ъ?$")
end
if base then
decl = "proper"
break
end
base = rmatch(lemma, "^(.*[еёо]́?в)ъ?$")
if base then
decl = "short"
break
end
base = rmatch(lemma, "(.*[иы]́н)ъ?$") --accented
if base then
decl = "stressed-short"
break
end
base = rmatch(lemma, "(.*[иы]н)ъ?$") --unaccented
if base then
decl = "mixed"
break
-- error("With -ин/ын adjectives, must specify 'short' or 'mixed':" .. lemma)
end
error("Cannot determine stem type of adjective: " .. lemma)
end
elseif m_table.contains({"short", "stressed-short", "mixed", "proper",
"stressed-proper"}, decl) then
base = rmatch(lemma, "^(.-)ъ?$")
assert(base)
break
elseif decl == "й" or decl == "й-short" then
base = rmatch(lemma, "^(.-)й$")
assert(base)
tr = com.strip_tr_ending(tr, "й")
decl = "й-short"
break
else
base = lemma
break
end
end
if not datedrare and (args.refl or not (decl == "ый" or decl == "ий" and not rfind(base, "[цс]к$"))) then
datedrare = "none"
end
return base, tr, decl, short_accent, short_stem, datedrare
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. бескра́йний with
-- dereduced nom sg бескра́ен without expected -ь.
local function add_bare_suffix(bare, baretr, old, decl, dereduced)
if decl == "й-short" then
return bare .. "й", baretr and baretr .. "j" or nil
elseif old and decl ~= "ій" and decl ~= "$" then
return bare .. "ъ", baretr
elseif decl == "ий" or decl == "ій" then
-- This next special case is mentioned in Zaliznyak's 1980 grammatical
-- dictionary for adjectives (footnote, p. 60).
if dereduced and rfind(bare, "[нН]$") then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "]́?$") then
-- This happens with adjectives like длинноше́ий, short masculine
-- singular длинноше́й.
return bare .. "й", baretr and baretr .. "j" or nil
else
return bare .. "ь", baretr and baretr .. "ʹ" or nil
end
else
return bare, baretr
end
end
-- Construct and set bare and short form in args, and canonicalize
-- short accent spec, handling cases *, (1) and (2). Return canonicalized
-- short accent and the short declension, which is usually the same as
-- the corresponding long one.
construct_bare_and_short_stem = function(args, short_accent, short_stem,
short_stemtr, accented_stem, accented_stemtr, old, decl)
-- Check if short forms allowed; if not, no short-form params can be given.
-- Construct bare version of stem; used for cases where the ending
-- is non-syllabic (i.e. short masculine singular of long adjectives,
-- and masculine singular of short, mixed and proper adjectives). Comes
-- from short masculine or 3rd argument if explicitly given, else from the
-- accented stem, possibly with the dereduction transformation applied
-- (if * occurs in the short accent spec).
local reducible, sc1, sc2
if short_accent then
short_accent, reducible = rsubb(short_accent, "%*", "")
short_accent, sc1 = rsubb(short_accent, "%(1%)", "")
short_accent, sc2 = rsubb(short_accent, "%(2%)", "")
end
if sc1 or sc2 then
-- Reducible isn't compatible with sc1 or sc2, but Zaliznyak's
-- dictionary always seems to notate sc1 and sc2 with reducible *,
-- so ignore it.
reducible = false
end
if sc1 and sc2 then
error("Special cases 1 and 2, i.e. (1) and (2), not compatible")
end
local short_decl = decl
-- Construct short stem. May be explicitly given, else comes from
-- end-accented stem.
if not short_stem then
short_stem, short_stemtr = accented_stem, accented_stemtr
end
-- Try to accent unaccented short stem (happens only when explicitly given),
-- but be conservative -- only if monosyllabic, since otherwise we have
-- no idea where stress should end up; after all, the explicit short stem
-- is for exceptional cases.
if not args.allow_unaccented then
if short_stemtr and com.is_unstressed(short_stem) ~= com.is_unstressed(short_stemtr) then
error("Explicit short stem " .. short_stem .. " and translit " .. short_stemtr .. " must have same accent pattern")
end
if com.is_monosyllabic(short_stem) then
short_stem, short_stemtr = com.make_ending_stressed(short_stem, short_stemtr)
elseif com.needs_accents(short_stem) then
error("Explicit short stem " .. short_stem .. " needs an accent")
end
end
if sc2 then
if not rfind(short_stem, "нн$") then
error("With special case 2, stem needs to end in -нн: " .. short_stem)
end
short_stem = rsub(short_stem, "нн$", "н")
if short_stemtr then
if not rfind(short_stemtr, "nn$") then
error("With special case 2, stem translit needs to end in -nn: " .. short_stemtr)
end
short_stemtr = rsub(short_stemtr, "nn$", "n")
end
end
-- Construct bare form, used for short masculine.
local bare, baretr
if reducible then
bare, baretr = com.dereduce_stem(short_stem, short_stemtr, rfind(short_accent, "^b"))
if not bare then
error("Unable to dereduce stem: " .. short_stem)
end
bare, baretr = add_bare_suffix(bare, baretr, old, decl, true)
else
bare, baretr = short_stem, short_stemtr
if sc1 then
if not rfind(bare, "нн$") then
error("With special case 1, stem needs to end in -нн: " .. bare)
end
bare = rsub(bare, "нн$", "н")
if baretr then
if not rfind(baretr, "nn$") then
error("With special case 1, stem translit needs to end in -nn: " .. baretr)
end
baretr = rsub(baretr, "nn$", "n")
end
end
-- With special case 1 or 2, we don't ever want -ь added, so treat
-- it like a reducible (that may be why these are marked as
-- reducible in Zaliznyak).
bare, baretr = add_bare_suffix(bare, baretr, old, decl, sc1 or sc2)
end
args.short_stem, args.short_stemtr = short_stem, short_stemtr
args.short_ustem, args.short_ustemtr = com.make_unstressed_once(short_stem, short_stemtr)
args.bare, args.baretr = bare, baretr
return short_accent, short_decl
end
--------------------------------------------------------------------------
-- Declensions --
--------------------------------------------------------------------------
declensions["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_p"] = "ые",
["gen_m"] = "ого",
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
declensions["ий"] = {
["nom_m"] = "ий",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_p"] = "ие",
["gen_m"] = "его",
["gen_f"] = "ей",
["gen_p"] = "их",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "им",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "им",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "ем",
["pre_f"] = "ей",
["pre_p"] = "их",
}
declensions["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_p"] = "ы́е",
["gen_m"] = "о́го",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
-- These can be stressed in ничья́ "draw, tie (in sports)".
declensions["ьий"] = {
["nom_m"] = "и́й",
["nom_n"] = "ье́",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ье́го",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ье́му",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ье́",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ье́м",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьём",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["short"] = {
["nom_m"] = "",
["nom_n"] = "о́",
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = "о́",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-short"] = mw.clone(declensions["short"])
declensions["stressed-short"]["pre_m"] = "е́"
declensions["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = "е́й",
["gen_p"] = "и́х",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́м",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́м",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ём",
["pre_f"] = "е́й",
["pre_p"] = "и́х",
}
declensions["mixed"] = {
["nom_m"] = "",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"ого", "а2"},
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = {"ому", "у2"},
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
internal_notes_table["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders["mixed"] = {"m"}
internal_notes_table_old["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders_old["mixed"] = {"m"}
declensions["proper"] = {
["nom_m"] = "",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "е́",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-proper"] = declensions["proper"]
for _, decl in ipairs({"proper", "stressed-proper"}) do
internal_notes_table[decl] = "<sup>1</sup> Rare."
internal_notes_table_old[decl] = "<sup>1</sup> Rare."
internal_notes_genders[decl] = {"f"}
internal_notes_genders_old[decl] = {"f"}
end
declensions["$"] = {
["nom_m"] = "",
["nom_n"] = "",
["nom_f"] = "",
["nom_p"] = "",
["gen_m"] = "",
["gen_f"] = "",
["gen_p"] = "",
["dat_m"] = "",
["dat_f"] = "",
["dat_p"] = "",
["acc_f"] = "",
-- don't do this; instead we default it to nom_n
-- ["acc_n"] = "",
["ins_m"] = "",
["ins_f"] = "",
["ins_p"] = "",
["pre_m"] = "",
["pre_f"] = "",
["pre_p"] = "",
-- for old-style templates, два, оба, compounds of два
["nom_mp"] = "",
["nom_fp"] = "",
["gen_mp"] = "",
["gen_fp"] = "",
["dat_mp"] = "",
["dat_fp"] = "",
-- don't do this; instead we default them to nom_mp, nom_fp
-- ["acc_mp"] = "",
-- ["acc_fp"] = "",
["ins_mp"] = "",
["ins_fp"] = "",
["pre_mp"] = "",
["pre_fp"] = "",
}
declensions_old["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_mp"] = "ые",
["nom_p"] = "ыя",
["gen_m"] = "аго",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["ій"] = {
["nom_m"] = "ій",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_mp"] = "іе",
["nom_p"] = "ія",
["gen_m"] = "яго",
["gen_f"] = "ей",
["gen_p"] = "ихъ",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "имъ",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "имъ",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "емъ",
["pre_f"] = "ей",
["pre_p"] = "ихъ",
}
declensions_old["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_mp"] = "ы́е",
["nom_p"] = "ы́я",
["gen_m"] = {"а́го", "о́го"},
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́мъ",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["ьій"] = {
["nom_m"] = "ій",
["nom_n"] = "ье",
["nom_f"] = "ья",
["nom_p"] = "ьи",
["gen_m"] = "ьяго",
["gen_f"] = "ьей",
["gen_p"] = "ьихъ",
["dat_m"] = "ьему",
["dat_f"] = "ьей",
["dat_p"] = "ьимъ",
["acc_f"] = "ью",
["acc_n"] = "ье",
["ins_m"] = "ьимъ",
["ins_f"] = {"ьей", "ьею"},
["ins_p"] = "ьими",
["pre_m"] = "ьемъ",
["pre_f"] = "ьей",
["pre_p"] = "ьихъ",
}
declensions_old["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́хъ",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́мъ",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́мъ",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьёмъ",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́хъ",
}
declensions_old["short"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = "а",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "у",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["stressed-short"] = mw.clone(declensions_old["short"])
declensions_old["stressed-short"]["pre_m"] = "ѣ́"
declensions_old["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = {"е́й", "ея́"},
["gen_p"] = "и́хъ",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́мъ",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́мъ",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ёмъ",
["pre_f"] = "е́й",
["pre_p"] = "и́хъ",
}
declensions_old["mixed"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"аго", "а1"},
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = {"ому", "у1"},
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["proper"] = {
["nom_m"] = "ъ",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "ѣ́",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["stressed-proper"] = declensions_old["proper"]
declensions_old["$"] = declensions["$"]
local function frob_genitive_masc(decl)
-- signal to combine_stem_and_suffix() to use the special tr_adj()
-- function so that -го gets transliterated to -vo
if type(decl["gen_m"]) == "table" then
local entries = {}
for _, entry in ipairs(decl["gen_m"]) do
table.insert(entries, rsub(entry, "го$", "го<adj>"))
end
decl["gen_m"] = entries
else
decl["gen_m"] = rsub(decl["gen_m"], "го$", "го<adj>")
end
end
-- Frob declensions, adding <adj> to gen_m forms ending in -го. This is
-- a signal to add manual translit early on that renders -го as -vo.
for _, decl in pairs(declensions_old) do
frob_genitive_masc(decl)
end
for _, decl in pairs(declensions) do
frob_genitive_masc(decl)
end
--------------------------------------------------------------------------
-- Declension functions --
--------------------------------------------------------------------------
local function attach_unstressed(args, suf, short)
local stem, stemtr
if short then
stem, stemtr = args.short_stem, args.short_stemtr
else
stem, stemtr = args.stem, args.stemtr
end
if suf == nil then
return nil
elseif nom.nonsyllabic_suffixes[suf] then
if not args.bare then
return nil
elseif rfind(args.bare, "[йьъ]$") then
return {args.bare, args.baretr}
elseif suf == "ъ" then
return com.concat_russian_tr(args.bare, args.baretr, suf, nil, "dopair")
else
return {args.bare, args.baretr}
end
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(stem, stemtr, suf, rules, args.old))
end
local function attach_stressed(args, suf, short)
local ustem, ustemtr
if short then
ustem, ustemtr = args.short_ustem, args.short_ustemtr
else
ustem, ustemtr = args.ustem, args.ustemtr
end
if suf == nil then
return nil
elseif not rfind(suf, "[ё́]") then -- if suf has no "ё" or accent marks
return attach_unstressed(args, suf, short)
end
local rules = nom.stressed_rules[ulower(usub(ustem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(ustem, ustemtr, suf, rules, args.old))
end
local function attach_both(args, suf, short)
local results = {}
-- Examples with stems with ё on Zaliznyak p. 61 list the
-- ending-stressed forms first, so go with that.
-- NOTE: This assumes we get one value returned, not a list of such values.
table.insert(results, attach_stressed(args, suf, short))
table.insert(results, attach_unstressed(args, suf, short))
return results
end
local function attach_with(args, suf, fun, short)
if type(suf) == "table" then
local all_combineds = {}
for _, x in ipairs(suf) do
local combineds = attach_with(args, x, fun, short)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
end
return all_combineds
else
local funval = fun(args, suf, short)
if funval then
local tbl = {}
assert(type(funval) == "table")
if type(funval[1]) ~= "table" then
funval = {funval}
end
for _, x in ipairs(funval) do
table.insert(tbl,
com.concat_paired_russian_tr(x, args.real_suffix))
end
return tbl
else
return {}
end
end
end
local function gen_form(args, decl, case, fun)
if not args.forms[case] then
args.forms[case] = {}
end
insert_forms_into_existing_forms(args.forms[case],
attach_with(args, decl[case], fun, false))
end
decline = function(args, decl, stressed)
local attacher = stressed and attach_stressed or attach_unstressed
for _, case in ipairs(long_cases) do
gen_form(args, decl, case, attacher)
end
end
canonicalize_override = function(args, case)
local val = args[case]
if not val then
return nil
end
val = rsplit(val, "%s*,%s*")
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(val) do
local ru, tr = com.split_russian_tr(v)
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
val = newvals
return val
end
handle_forms_and_overrides = function(args, short_forms_allowed)
local f = args.forms
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
for _, case in ipairs(long_cases) do
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
args[case] = canonicalize_override(args, case) or f[case]
end
for _, case in ipairs(short_cases) do
if short_forms_allowed then
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
if args.shorttailall then
append_note_all(case, args.shorttailall)
end
if args.shorttail then
append_note_last(case, args.shorttail, ">1")
end
args[case] = canonicalize_override(args, case) or f[case]
else
args[case] = nil
end
end
-- Convert an empty list to nil, so that an mdash is inserted. This happens,
-- for example, with words like голубой where args.bare is set to nil.
for _, case in ipairs(all_cases) do
if args[case] and #args[case] == 0 then
args[case] = nil
end
end
-- default acc_n to nom_n; applies chiefly in the indeclinable declension
-- (used with manual declension tables)
if not args.acc_n then
args.acc_n = args.nom_n
end
-- default inanimate/animate accusative variants as appropriate; this is
-- almost always correct, but not with e.g. два́дцать оди́н, where the
-- masculine animate accusative два́дцать одного́ differs from both the
-- masculine nominative два́дцать оди́н and the masculine genitive
-- двадцати́ одного́.
if not args.acc_m_an then
args.acc_m_an = args.gen_m
end
if not args.acc_m_in then
args.acc_m_in = args.nom_m
end
-- Compounds of два do not have animacy; everything else does.
-- Only copy either the with-animacy or without-animacy variants to avoid
-- having both forms in {{ru-generate-adj-forms}}.
if args.special ~= "cdva" then
if not args.acc_p_an then
args.acc_p_an = args.gen_p
end
if not args.acc_p_in then
args.acc_p_in = args.nom_p
end
if not args.acc_mp_an then
args.acc_mp_an = args.gen_mp
end
if not args.acc_mp_in then
args.acc_mp_in = args.nom_mp
end
if not args.acc_fp_an then
args.acc_fp_an = args.gen_fp
end
if not args.acc_fp_in then
args.acc_fp_in = args.nom_fp
end
else
if not args.acc_mp then
args.acc_mp = args.nom_mp
end
if not args.acc_fp then
args.acc_fp = args.nom_fp
end
end
end
--------------------------------------------------------------------------
-- Short adjective declension --
--------------------------------------------------------------------------
short_declensions["ый"] = { m="", f="а́", n="о́", p="ы́" }
short_declensions["ой"] = short_declensions["ый"]
short_declensions["ий"] = { m="ь", f="я́", n="е́", p="и́" }
short_declensions_old["ый"] = { m="ъ", f="а́", n="о́", p="ы́" }
short_declensions_old["ой"] = short_declensions_old["ый"]
short_declensions_old["ій"] = short_declensions["ий"]
-- Short adjective stress patterns:
-- "-" = stem-stressed
-- "+" = ending-stressed (drawn onto the last syllable of stem in masculine)
-- "-+" = both possibilities
short_stress_patterns["a"] = { m="-", f="-", n="-", p="-" }
short_stress_patterns["a'"] = { m="-", f="-+", n="-", p="-" }
short_stress_patterns["b"] = { m="+", f="+", n="+", p="+" }
short_stress_patterns["b'"] = { m="+", f="+", n="+", p="-+" }
short_stress_patterns["c"] = { m="-", f="+", n="-", p="-" }
short_stress_patterns["c'"] = { m="-", f="+", n="-", p="-+" }
short_stress_patterns["c''"] = { m="-", f="+", n="-+", p="-+" }
local function gen_short_form(args, decl, case, fun, datedrare)
if not args.forms["short_" .. case] then
args.forms["short_" .. case] = {}
end
local inserted = insert_forms_into_existing_forms(
args.forms["short_" .. case], attach_with(args, decl[case], fun, true),
(datedrare == "dated" and datedrare == "rare") and "*" or nil)
if datedrare == "dated" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Dated.")
elseif datedrare == "rare" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Rare.")
end
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
["-+"] = attach_both,
}
decline_short = function(args, decl, stress_pattern, dated)
if stress_pattern then
for _, case in ipairs({"m", "f", "n", "p"}) do
gen_short_form(args, decl, case, attachers[stress_pattern[case]],
dated)
end
end
end
--------------------------------------------------------------------------
-- Create the table --
--------------------------------------------------------------------------
local title_temp = [=[Declension of <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local old_title_temp = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local title_temp_no_short_msg = [=[Declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local old_title_temp_no_short_msg = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local template = nil
local full_clause = nil
local template_no_neuter = nil
local full_clause_no_neuter = nil
local surname_full_clause = nil
local template_mp = nil
local full_clause_mp = nil
local template_mp_no_neuter = nil
local full_clause_mp_no_neuter = nil
local surname_full_clause_mp = nil
local template_dva = nil
local full_clause_dva = nil
local full_clause_compound_dva = nil
local template_oba = nil
local full_clause_oba = nil
local short_clause_separator = nil
local short_clause = nil
local short_clause_no_neuter_separator = nil
local short_clause_no_neuter = nil
local short_clause_mp_separator = nil
local short_clause_mp = nil
local short_clause_mp_no_neuter_separator = nil
local short_clause_mp_no_neuter = nil
local internal_notes_template = nil
local notes_template = nil
local function get_accel_forms(old, special, has_nom_mp)
return {
-- used with all variants
nom_m = "nom|m|s",
nom_f = "nom|f|s",
nom_n = "nom|n|s",
-- not used with special; applies to all genders normally but only
-- feminine and neuter with old=1
nom_p = old and has_nom_mp and "nom|f//n|p" or "nom|p",
-- only used with old=1 or special; applies to the masculine and neuter if
-- special, but only masculine if old=1
nom_mp = special and "nom|m//n|p" or "nom|m|p",
-- only used with special
nom_fp = "nom|f|p",
-- the remaining singulars and non-gendered plurals used with all variants
-- except special == "oba"
gen_m = "gen|m//n|s",
gen_f = "gen|f|s",
gen_p = "gen|p",
dat_m = "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",
-- the following two not used with special in ("dva", "oba"); applies to
-- all genders normally but only feminine and neuter with old=1
acc_p_an = old and has_nom_mp and "an|acc|f//n|p" or "an|acc|p",
acc_p_in = old and has_nom_mp and "in|acc|f//n|p" or "in|acc|p",
-- the following two only used with old=1 or special in ("dva|oba");
-- applies to the masculine and neuter if special, but only masculine if
-- old=1
acc_mp_an = special and "an|acc|m//n|p" or "an|acc|m|p",
acc_mp_in = special and "in|acc|m//n|p" or "in|acc|m|p",
-- the following two only used with special in ("dva", "oba")
acc_fp_an = "an|acc|f|p",
acc_fp_in = "in|acc|f|p",
-- the next 6 are used with all variants except special == "oba"
ins_m = "ins|m//n|s",
ins_f = "ins|f|s",
ins_p = "ins|p",
pre_m = "pre|m//n|s",
pre_f = "pre|f|s",
pre_p = "pre|p",
-- the following two gendered plurals are only used with special == "cdva"
acc_mp = "acc|m//n|p",
acc_fp = "acc|f|p",
-- the remaining gendered plurals are only used with special == "oba"
gen_mp = "gen|m//n|p",
gen_fp = "gen|f|p",
dat_mp = "dat|m//n|p",
dat_fp = "dat|f|p",
ins_mp = "ins|m//n|p",
ins_fp = "ins|f|p",
pre_mp = "pre|m//n|p",
pre_fp = "pre|f|p",
-- short forms
short_m = "short|m|s",
short_f = "short|f|s",
short_n = "short|n|s",
short_p = "short|p",
}
end
-- Make the table
make_table = function(args)
local lemma_forms = args.special and args.nom_mp or
args.nofull and args.short_m or args.nom_m
args.lemma = m_links.remove_links(nom.show_form(lemma_forms, true, nil, nil))
args.title = args.title or strutils.format(
(args.special or args.manual) and args.old and old_title_temp_no_short_msg or
(args.special or args.manual) and title_temp_no_short_msg or
args.old and old_title_temp or
title_temp,
args)
local has_nom_mp = args.nom_mp and not (#args.nom_mp == 1 and args.nom_mp[1][1] == "-")
local accel_forms = get_accel_forms(args.old, args.special, has_nom_mp)
for _, case in ipairs(all_cases) do
if args[case] then
local accel_form = accel_forms[case]
if not accel_form then
error("Internal error: Unrecognized case " .. case .. " when looking up accelerator form")
end
if args.noneuter or args.real_surname then
accel_form = rsub(accel_form, "//n", "")
end
if args.real_surname then
accel_form = rsub(accel_form, "an|", "")
end
args[case] = nom.show_form(args[case], false, accel_form, lemma_forms)
else
args[case] = nil
end
end
local temp, fullc
if args.special == "oba" then
temp = template_oba
fullc = full_clause_oba
elseif args.special == "dva" then
temp = template_dva
fullc = full_clause_dva
elseif args.special == "cdva" then
temp = template_dva -- no template_cdva
fullc = full_clause_compound_dva
elseif args.real_surname and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = surname_full_clause_mp
elseif args.real_surname then
temp = template_no_neuter
fullc = surname_full_clause
elseif args.noneuter and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = full_clause_mp_no_neuter
elseif args.noneuter then
temp = template_no_neuter
fullc = full_clause_no_neuter
elseif args.old and has_nom_mp then
temp = template_mp
fullc = full_clause_mp
else
temp = template
fullc = full_clause
end
if args.old then
if has_nom_mp then
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_mp_no_neuter_separator or short_clause_mp_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_mp_no_neuter or short_clause_mp, args)
else
args.short_clause = ""
end
else
args.short_clause = ""
end
else
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_no_neuter_separator or short_clause_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_no_neuter or short_clause, args)
else
args.short_clause = ""
end
end
if not args.nofull then
args.full_clause = strutils.format(fullc, args)
else
args.full_clause = ""
end
args.internal_notes = table.concat(args.internal_notes, "<br />")
args.internal_notes_clause = #args.internal_notes > 0 and strutils.format(internal_notes_template, args) or ""
args.notes_clause = args.notes and strutils.format(notes_template, args) or ""
return strutils.format(temp, args)
end
-- Used for new-style templates
short_clause_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for new-style templates
short_clause = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for new-style templates
short_clause_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=5 |
|-
]===]
-- Used for new-style templates
short_clause_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=7 |
|-
]===]
-- Used for old-style templates
short_clause_mp = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for old-style templates
short_clause_mp_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for both new-style and old-style templates
notes_template = [===[
<div style="width:100%;text-align:left">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
-- Used for both new-style and old-style templates
internal_notes_template = rsub(notes_template, "notes", "internal_notes")
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue)">{title}</div>
<div class="NavContent">
{\op}| style="background:var(--wikt-palette-paleblue);text-align:center" class="inflection-table"
|-
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[{full_clause}|-{short_clause}
|{\cl}{internal_notes_clause}{notes_clause}</div></div></div>]===]
end
-- Used for both new-style and old-style templates
template = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
template_no_neuter = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
surname_full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for old-style templates
template_mp = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်/ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for old-style templates
template_mp_no_neuter = template_prelude("60") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for some old-style templates
surname_full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for два and compounds
template_dva = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်/နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of два (only for два itself,
-- which has an animacy distinction; not for compounds)
full_clause_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for both new-style and old-style templates of compounds of два
full_clause_compound_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=4 | {acc_mp}
| data-accel-col=5 | {acc_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for оба
template_oba = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်နပုလ္လိၚ်/ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of оба
full_clause_oba = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_mp}
| data-accel-col=5 | {gen_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_mp}
| data-accel-col=5 | {dat_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_mp_an}
| data-accel-col=5 | {acc_fp_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_mp}
| data-accel-col=5 | {ins_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_mp}
| data-accel-col=5 | {pre_fp}
]===]
return export
kl0fgi27epxsvsyf9ycfa0b3o36l7mp
399865
399862
2026-07-23T00:53:03Z
Intobesa.bot
1035
Bot: ပွမကၠာဲစုတ်ယၟုနူဘာသာအၚ်္ဂလိက်
399865
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
adjectives.
Author: Benwing, rewritten from early version by Wikitiki89
Arguments:
1: lemma; nom sg, or just the stem if an explicit declension type is
given in arg 2
2: declension type (usually omitted to autodetect based on the lemma),
along with any short accent type and optional irregular short stem;
see below.
CASE_NUMGEN: Override a given form; see abbreviations below
suffix: any suffix to attach unchanged to the end of each form
notes: Notes to add to the end of the table
title: Override the title
shorttail: Footnote (e.g. *, 1, 2, etc.) to add to short forms if
there's more than one; automatically superscripted
shorttailall: Same as shorttail= but applies to all short forms even
if there's only one
CASE_NUMGEN_tail: Like shorttailall but only for a specific form
nofull: Short forms only
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
short: short form
Number/gender abbreviations:
m: masculine singular
n: neuter singular
f: feminine singular
p: plural
mp: masculine plural (old-style and special numeral tables only)
fp: masculine plural (special numeral tables only)
Animacy abbreviations:
an: animate
in: inanimate
Declension-type argument (arg 2):
Form is DECLSPEC or DECLSPEC,DECLSPEC,... where DECLSPEC is
one of the following:
DECLTYPE:SHORTACCENT:SHORTSTEM
DECLTYPE:SHORTACCENT
DECLTYPE
SHORTACCENT:SHORTSTEM
SHORTACCENT
(blank)
DECLTYPE should normally be omitted, and the declension autodetected
from the ending; or it should be ь, to indicate that an adjective
in -ий is of the possessive variety with an extra -ь- in most of
the endings. Alternatively, it can be an explicit declension type,
in which case the lemma field needs to be replaced with the bare
stem; the following are the possibilities:
ый ий ой ьий short mixed manual (new-style)
ый ій ьій short stressed-short mixed proper stressed-proper
ъ-short ъ-stressed-short ъ-mixed ъ-proper ъ-stressed-proper
manual (old-style, where ъ-* is a synonym for *, for any *)
SHORTACCENT is one of a a' b b' c c' c'' to auto-generate the
short forms with the specified accent pattern (following
Zaliznyak); if omitted, no short forms will be auto-generated.
SHORTACCENT can contain a * in it for "reducible" adjectives,
where the short masculine singular has an epenthetic vowel
in the final syllable. It can also contain (1) or (2) to
indicate special cases. Both are used in conjunction with
adjectives in -нный/-нний. Special case (1) causes the
short masculine singular to end in -н instead of -нн; special
case (2) causes all short forms to end this way.
SHORTSTEM, if present, is used as the short stem to base the
short forms off of, instead of the normal adjective long stem
(possibly with a final-syllable accent added in the case of
declension type -о́й).
TODO:
1. Figure out what the symbol X-inside-square (⊠) means, which seems to go with
all adjectives in -о́й with multi-syllabic stems. It may mean that the
masculine singular short form is missing. If this indeed a regular thing,
we need to implement it (and if it's regular but means something else,
we need to implement that, too). Also figure out what the other signs
on pages 68-76 etc. mean: -, X, ~, П₂, Р₂, diamond (♢), triangle (△; might
simply mean a misc. irregularity; explained on p. 61).
2. Mark irregular overridden forms with △ (esp. appropriate for short forms).
3. Should non-reducible adjectives in -нный and -нний default to special case
(1)?
4. In the case of a non-dereducible short masc sing of stress type b, we don't
currently move the stress to the last syllable. Should we?
5. FIXME: In decline(), we used to default acc_n to nom_n. Now we do that in
handle_forms_and_overrides(). Verify that this is more correct.
6. FIXME: Allow multiple heads, both to handle cases where two manual translits
exist (or rather, one automatic and one manual), and cases where two
stresses are possible, e.g. мину́вший or ми́нувший.
7. FIXME: Add code to generate the regular comparative. The rules are as
follows: If the stem doesn't end in к г х, add -ee with no stress change
if the short form is type a, else add -е́е (including type a'). If the stem
ends in к г х, turn the last consonant into ч ж ш, add -е, and place the
stress on the syllable preceding the ending. (E.g. дорого́й -> доро́же)
]=]--
local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_table = require("Module:table")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local strutils = require("Module:string utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
----------------------------- Utility functions ------------------------
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local usub = mw.ustring.sub
-- 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
-- Insert a single form (consisting of {RUSSIAN, TR}) or a list of such
-- forms into an existing list of such forms, adding NOTESYM (a string or nil)
-- to the new forms if not nil. Return whether an insertion was performed.
local function insert_forms_into_existing_forms(existing, newforms, notesym)
if type(newforms) ~= "table" then
newforms = {newforms}
end
local inserted = false
for _, item in ipairs(newforms) do
if not m_table.contains(existing, item) then
if notesym then
item = com.concat_paired_russian_tr(item, {notesym})
end
table.insert(existing, item)
inserted = true
end
end
return inserted
end
local function track(page)
m_debug.track("ru-adjective/" .. page)
return true
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-------------------- Global declension/case/etc. variables -------------------
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
local declensions = {}
local declensions_old = {}
local internal_notes_table = {}
local internal_notes_table_old = {}
local internal_notes_genders = {}
local internal_notes_genders_old = {}
local short_declensions = {}
local short_declensions_old = {}
-- Formerly used for the ой-rare type, which has been removed; but keep
-- the code around in case we need it later.
local short_internal_notes_table = {}
local short_internal_notes_table_old = {}
local short_stress_patterns = {}
local long_cases = {
"nom_m", "nom_n", "nom_f", "nom_p",
"gen_m", "gen_f", "gen_p",
"dat_m", "dat_f", "dat_p",
"acc_m_an", "acc_m_in", "acc_p_an", "acc_p_in", "acc_f", "acc_n",
"ins_m", "ins_f", "ins_p",
"pre_m", "pre_f", "pre_p",
-- extra old long cases
"nom_mp",
"acc_mp_an", "acc_mp_in",
-- extra dva cases
"nom_fp",
"acc_fp_an", "acc_fp_in",
-- extra oba cases
"gen_mp", "gen_fp",
"dat_mp", "dat_fp",
"ins_mp", "ins_fp",
"pre_mp", "pre_fp",
-- extra cases for compounds of два
"acc_mp", "acc_fp",
}
-- Short cases and corresponding numbered arguments
local short_cases = {
"short_m", "short_n", "short_f", "short_p"
}
-- Create master list of all possible cases (actually case/number/gender pairs)
local all_cases = mw.clone(long_cases)
for _, case in ipairs(short_cases) do
m_table.insertIfNot(all_cases, case)
end
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same.
local test_new_ru_adjective_module = false
-- Forward references to functions
local tracking_code
local categorize
local detect_stem_and_accent_type
local construct_bare_and_short_stem
local decline
local canonicalize_override
local handle_forms_and_overrides
local decline_short
local make_table
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Implementation of main entry point
function export.do_generate_forms(args, old, manual)
local orig_args
if test_new_ru_adjective_module then
orig_args = mw.clone(args)
end
if args[3] or args[4] or args[5] or args[6] then
error("Numbered short forms no longer supported")
end
if args.shorttailall then
track("shorttailall")
end
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
args.forms = {}
args.categories = {}
old = old or args.old
args.old = old
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
args.internal_notes = {}
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
if args.notes then
local notes, entry = m_table_tools.get_initial_notes(args.notes)
args.notes = notes .. entry
end
local overall_short_forms_allowed
manual = manual or args[2] == "manual"
args.manual = manual
local decl_types = manual and "$" or args[2] or ""
local lemmas = manual and "-" or args[1] or SUBPAGENAME
local normal_short_classes, rare_short_classes, dated_short_classes
local saw_no_short
for _, lemma_and_tr in ipairs(rsplit(lemmas, ",")) do
-- reset these for each lemma so we get the short classes of the last
-- lemma (doesn't really matter, as they should be the same for all
-- lemmas)
normal_short_classes = {}
rare_short_classes = {}
dated_short_classes = {}
saw_no_short = false
for _, decl_type in ipairs(rsplit(decl_types, ",")) do
local lemma, lemmatr = com.split_russian_tr(lemma_and_tr)
-- if lemma ends with -ся, strip it and act as if suffix=ся given
-- (or rather, prepend ся to suffix)
local active_base = rmatch(lemma, "^(.*)ся$")
if active_base then
lemma = active_base
lemmatr = com.strip_tr_ending(lemmatr, "ся")
args.refl = true
args.real_suffix = com.concat_paired_russian_tr({"ся"}, args.suffix)
else
args.refl = false
args.real_suffix = args.suffix
end
-- Auto-detect actual decl type, and get short accent and overriding
-- short stem, if specified.
local stem, stemtr, short_accent, short_stem, short_stemtr, datedrare
stem, stemtr, decl_type, short_accent, short_stem, datedrare =
detect_stem_and_accent_type(lemma, lemmatr, decl_type, args)
if rfind(decl_type, "^[іи]й$") and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl_type = "ый"
end
if datedrare == "none" then
saw_no_short = true
end
local proper_decl = m_table.contains({"proper", "stressed-proper"}, decl_type)
-- Use args.real_surname to avoid overwriting args.surname, since we may be overwriting
-- `args` multiple times. FIXME: Use a separate data structure for this.
args.real_surname = proper_decl or args.surname
local short_title
if short_accent then
short_title = short_accent
elseif args.real_surname then
short_title = "surname"
elseif m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed"}, decl_type) then
short_title = "possessive"
end
if short_title then
if datedrare == "dated" then
m_table.insertIfNot(dated_short_classes, short_title)
elseif datedrare == "rare" then
m_table.insertIfNot(rare_short_classes, short_title)
else
m_table.insertIfNot(normal_short_classes, short_title)
end
end
if short_stem then
short_stem, short_stemtr = com.split_russian_tr(short_stem)
end
stem, args.allow_unaccented = rsubb(stem, "^%*", "")
if args.allow_unaccented then
track("allow-unaccented")
end
-- Treat suffixes without an accent, and suffixes with an accent on
-- the initial hyphen, as if they were preceded with a *, which
-- overrides all the logic that normally (a) normalizes the accent,
-- and (b) complains about multisyllabic words without an accent.
-- Don't do this if lemma is just -, which is used specially in
-- manual declension tables.
if lemma ~= "-" and (rfind(lemma, "^%-́") or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
if not args.allow_unaccented and com.needs_accents(lemma) then
-- Technically we don't need accents in -ой adjectives (which are
-- always ending-stressed) and in -ый adjectives with a monosyllabic
-- stem, such as полный (which are always stem-stressed), but it's
-- better to enforce accents in all multisyllabic words, for
-- consistency with nouns and verbs. Note that we still don't
-- require an accent in monosyllabic adjectives such as злой.
error("Lemma must have an accent in it: " .. lemma)
end
-- Set stem and unstressed version. Also construct end-accented version
-- of stem if unstressed; needed for short forms of adjectives of
-- type -о́й. We do this here before doing the dereduction
-- transformation so that we don't end up stressing an unstressed
-- epenthetic vowel, and so that the previous syllable instead ends
-- up stressed (in type -о́й adjectives the stem won't have any stress).
-- Note that the closest equivalent in nouns is handled in
-- attach_unstressed(), which puts the stress onto the final syllable
-- if the stress pattern calls for ending stress in the genitive
-- plural. This works there because
-- (1) It won't stress an unstressed epenthetic vowel because the
-- cases where the epenthetic vowel is unstressed are precisely
-- those with stem stress in the gen pl, not ending stress;
-- (2) There isn't a need to stress the syllable preceding an
-- unstressed epenthetic vowel because that syllable should
-- already have stress, since we require that the base stem form
-- (parameter 2) have stress in it whenever any case form has
-- stem stress. This isn't the case here in type -о́й adjectives.
-- NOTE: FIXME: I can't actually quote any forms from Zaliznyak
-- (at least not from pages 58-60, where this is discussed) that
-- seem to require last-stem-syllable-stress, i.e. where the stem is
-- multisyllabic. The two examples given are both unusual: дорого́й
-- has stress on the initial syllable до́рог etc. and these forms are
-- marked with a triangle (indicating an apparent irregularity); and
-- голубо́й seems not to have a masculine singular short form, and it's
-- accent pattern b, so the remaining forms are all ending-stressed.
-- In fact it's possible that these examples don't exist: It appears
-- that all the multisyllabic adjectives in -о́й listed in the
-- dictionary have a marking next to them consisting of an X inside of
-- a square, which is glossed p. 69 to something I don't understand,
-- but may be saying that the masculine singular short form is
-- missing. If this is regular, we need to implement it.
args.stem, args.stemtr = stem, stemtr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, stemtr)
local accented_stem, accented_stemtr = stem, stemtr
if not args.allow_unaccented then
if accented_stemtr and com.is_unstressed(accented_stem) ~= com.is_unstressed(accented_stemtr) then
error("Stem " .. accented_stem .. " and translit " .. accented_stemtr .. " must have same accent pattern")
end
if com.is_unstressed(accented_stem) then
accented_stem, accented_stemtr =
com.make_ending_stressed(accented_stem, accented_stemtr)
end
end
local short_forms_allowed = manual and true or decl_type == "ый" or
decl_type == "ой" or decl_type == (old and "ій" or "ий")
overall_short_forms_allowed = overall_short_forms_allowed or
short_forms_allowed
if not short_forms_allowed then
-- FIXME: We might want to allow this in case we have a
-- reducible short, mixed or proper possessive adjective. But
-- in that case we need to reduce rather than dereduce to get
-- the stem.
if short_accent or short_stem then
error("Cannot specify short accent or short stem with declension type " .. decl_type .. ", as short forms aren't allowed")
end
if args.short_m or args.short_f or args.short_n or args.short_p then
error("Cannot specify explicit short forms with declension type " .. decl_type .. ", as short forms aren't allowed")
end
end
local orig_short_accent = short_accent
local short_decl_type
short_accent, short_decl_type = construct_bare_and_short_stem(args,
short_accent, short_stem, short_stemtr, accented_stem,
accented_stemtr, old, decl_type)
local decls = old and declensions_old or declensions
local short_decls = old and short_declensions_old or short_declensions
if not decls[decl_type] then
error("Unrecognized declension type " .. decl_type)
end
if short_accent == "" then
error("Short accent type cannot be blank, should be omitted or given")
end
if short_accent and not short_stress_patterns[short_accent] then
error("Unrecognized short accent type " .. short_accent)
end
tracking_code(decl_type, args, orig_short_accent, short_accent,
short_stem, datedrare, short_forms_allowed)
if not manual and enable_categories then
categorize(decl_type, args, orig_short_accent, short_accent,
short_stem)
end
decline(args, decls[decl_type], m_table.contains({"ой", "ьей", "й-short", "stressed-short", "stressed-proper"}, decl_type))
if short_forms_allowed and short_accent then
decline_short(args, short_decls[short_decl_type],
short_stress_patterns[short_accent], datedrare)
end
local intable = old and internal_notes_table_old or internal_notes_table
local shortintab = old and short_internal_notes_table_old or
short_internal_notes_table
local internal_note = intable[decl_type] or shortintab[short_decl_type]
if internal_note then
m_table.insertIfNot(args.internal_notes, internal_note)
end
end
end
local short_class_titles = {}
local function make_short_class_title(short_classes, datedrare)
local sct = table.concat(short_classes, ",") -- short class title
if sct == "" then
return
end
if not m_table.contains({"surname", "possessive"}, sct) then
-- Convert e.g. a*,a(1) into a*[(1)], either finally or followed by
-- comma.
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%))$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%)),", "%1*[%2],")
-- Same for a(1),a*.
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*,", "%1*[%2],")
-- Convert (1), (2) to ①, ②.
sct = rsub(sct, "%(1%)", "①")
sct = rsub(sct, "%(2%)", "②")
-- Add a * before ①, ②, consistent with Zaliznyak.
sct = rsub(sct, "([abc]'*)([①②])", "%1*%2")
-- Convert ' and '' to ʹ and ʺ, consistent with Zaliznyak.
sct = sct:gsub("''", "ʺ"):gsub("'", "ʹ")
if args.nofull then
sct = "short-form-only class " .. sct
else
sct = "short class " .. sct
end
end
if datedrare then
sct = datedrare .. " " .. sct
end
table.insert(short_class_titles, sct)
end
make_short_class_title(normal_short_classes, nil)
make_short_class_title(rare_short_classes, "rare")
make_short_class_title(dated_short_classes, "dated")
if #short_class_titles == 0 then
if saw_no_short then
args.short_class_title = "no short forms"
else
args.short_class_title = "unknown short forms"
end
else
args.short_class_title = table.concat(short_class_titles, " / ")
end
handle_forms_and_overrides(args, overall_short_forms_allowed)
-- Test code to compare existing module to new one.
if test_new_ru_adjective_module then
local m_new_ru_adjective = require("Module:User:Benwing2/ru-adjective")
local newargs = m_new_ru_adjective.do_generate_forms(orig_args, old, manual)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
if not m_table.deepEquals(arg, newarg) then
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
if not difdecl then
track("same-decl")
end
end
return args
end
local function process_params(frame, include_form)
local boolean = {type = "boolean"}
local params = {
[1] = true,
[2] = true,
suffix = true,
title = true,
special = true,
shorttail = true,
shorttailall = true,
notes = true,
old = boolean,
noneuter = boolean,
nofull = boolean,
surname = boolean,
pronoun = boolean
}
if include_form then
params.form = {required = true}
end
for _, case in ipairs(all_cases) do
params[case] = true
params[case .. "_tail"] = true
params[case .. "_tailall"] = true
end
return require("Module:parameters").process(frame:getParent().args, params)
end
-- Implementation of main entry point
local function do_show(frame, old, manual)
local args = export.do_generate_forms(process_params(frame), old, manual)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- The main entry point for manual declension tables.
function export.show_manual(frame)
return do_show(frame, false, "manual")
end
-- The main entry point for manual old declension tables.
function export.show_manual_old(frame)
return do_show(frame, true, "manual")
end
-- Entry point for use in Module:ru-noun.
function export.get_nominal_decl(decl, gender, old)
local d = old and declensions_old[decl] or declensions[decl]
local n = {}
if gender == "m" then
n.nom_sg = d.nom_m
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
elseif gender == "f" then
n.nom_sg = d.nom_f
n.gen_sg = d.gen_f
n.dat_sg = d.dat_f
n.acc_sg = d.acc_f
n.ins_sg = d.ins_f
n.pre_sg = d.pre_f
elseif gender == "n" then
n.nom_sg = d.nom_n
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.acc_sg = d.acc_n
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
else
assert(false, "Unrecognized gender: " .. gender)
end
n.nom_pl = d.nom_p
n.gen_pl = d.gen_p
n.dat_pl = d.dat_p
n.ins_pl = d.ins_p
n.pre_pl = d.pre_p
if gender == "m" and d.nom_mp then
n.nom_pl = d.nom_mp
end
local intable = old and internal_notes_table_old or internal_notes_table
local ingenders = old and internal_notes_genders_old or internal_notes_genders
-- FIXME, what if there are multiple internal notes? See comment in
-- do_generate_forms().
local internal_notes = ingenders[decl] and m_table.contains(ingenders[decl], gender) and intable[decl]
return n, internal_notes
end
local function get_form(forms)
local canon_forms = {}
for _, form in ipairs(forms) do
local ru, tr = form[1], form[2]
local ruentry = m_table_tools.get_notes(ru)
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.get_notes(tr)
end
ruentry = m_links.remove_links(ruentry)
m_table.insertIfNot(canon_forms, {ruentry, trentry})
end
return com.concat_forms(canon_forms)
end
-- The entry point for 'ru-adj-forms' to generate all adjective forms.
function export.generate_forms(frame)
local args = export.do_generate_forms(process_params(frame), false)
local ins_text = {}
for _, case in ipairs(all_cases) do
if args[case] then
table.insert(ins_text, case .. "=" .. get_form(args[case]))
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-adj-form' to generate a particular adjective form.
function export.generate_form(frame)
local args = process_params(frame, "include form")
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
tracking_code = function(decl_class, args, orig_short_accent, short_accent,
short_stem, datedrare)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
local function dotrack(prefix)
if prefix ~= "" then
track(prefix)
prefix = prefix .. "/"
end
track(prefix .. decl_class)
for _, hint_type in ipairs(hint_types) do
track(prefix .. hint_type)
track(prefix .. decl_class .. "/" .. hint_type)
end
end
dotrack("")
if args.short_m or args.short_f or args.short_n or args.short_p then
dotrack("short")
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
dotrack("reducible")
dotrack("reducible/" .. short_accent)
end
if rfind(orig_short_accent, "%(1%)") then
dotrack("special-case-1")
dotrack("special-case-1/" .. short_accent)
end
if rfind(orig_short_accent, "%(2%)") then
dotrack("special-case-2")
dotrack("special-case-2/" .. short_accent)
end
end
if short_accent then
dotrack("short-accent/" .. short_accent)
if datedrare == "dated" then
dotrack("short-accent-dated")
dotrack("short-accent-dated/" .. short_accent)
elseif datedrare == "rare" then
dotrack("short-accent-rare")
dotrack("short-accent-rare/" .. short_accent)
end
elseif datedrare == "none" then
dotrack("short-accent/none")
else
dotrack("short-accent/unknown")
end
if short_stem then
dotrack("explicit-short-stem")
dotrack("explicit-short-stem/" .. short_accent)
end
for _, case in ipairs(all_cases) do
if args[case] then
track("irreg/" .. case)
-- questionable use: dotrack("irreg/" .. case)
end
end
end
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the part of speech.
local function insert_category(categories, cat, plpos)
-- table.insert(categories, "Russian " .. rsub(cat, "~", plpos))
end
categorize = function(decl_type, args, orig_short_accent, short_accent,
short_stem)
local plpos = args.real_surname and "surnames" or args.pronoun and "pronouns" or "adjectives"
-- Insert category CAT into the list of categories in ARGS.
local function insert_cat(cat)
-- insert_category(args.categories, cat, plpos)
end
-- FIXME: For compatibility with old {{temp|ru-adj7}}, {{temp|ru-adj8}},
-- {{temp|ru-adj9}}; maybe there's a better way.
if m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed",
"proper", "stressed-proper"}, decl_type) then
-- insert_cat("possessive ~")
end
if not args.pronoun then
if m_table.contains({"ьій", "ьий", "ьей"}, decl_type) then
-- insert_cat("long possessive ~")
elseif m_table.contains({"short", "stressed-short", "й-short"}, decl_type) then
-- insert_cat("short possessive ~")
elseif m_table.contains({"mixed"}, decl_type) then
-- insert_cat("mixed possessive ~")
elseif m_table.contains({"proper", "stressed-proper"}, decl_type) then
-- Don't insert a category like [[:Category:Russian proper-name surnames]]. Instead, rely on
-- [[:Category:Russian possessive surnames]] generated above.
if not args.real_surname then
-- insert_cat("proper-name ~")
end
elseif decl_type == "$" then
-- insert_cat("indeclinable ~")
else
local hint_types = com.get_stem_trailing_letter_type(args.stem)
-- insert English version of Zaliznyak stem type
local stem_type =
m_table.contains(hint_types, "velar") and "velar-stem" or
m_table.contains(hint_types, "sibilant") and "sibilant-stem" or
m_table.contains(hint_types, "c") and "ц-stem" or
m_table.contains(hint_types, "i") and "i-stem" or
m_table.contains(hint_types, "vowel") and "vowel-stem" or
m_table.contains(hint_types, "soft-cons") and "vowel-stem" or
m_table.contains(hint_types, "palatal") and "vowel-stem" or
decl_type == "ий" and "soft-stem" or
"hard-stem"
if stem_type == "soft-stem" or stem_type == "vowel-stem" then
-- insert_cat(stem_type .. " ~")
else
-- insert_cat(stem_type .. " " .. (m_table.contains({"ой", "ьей", "й-short"}, decl_type) and "ending-stressed" or "stem-stressed") .. " ~")
end
end
if m_table.contains({"ой", "ьей", "й-short"}, decl_type) then
-- insert_cat("ending-stressed ~")
end
end
local short_forms_allowed = m_table.contains({"ый", "ой", "ій", "ий"}, decl_type)
if short_forms_allowed then
local override_m = args.short_m
local override_f = args.short_f
local override_n = args.short_n
local override_p = args.short_p
local has_short = short_accent or override_m or override_f or
override_n or override_p
local missing_short = override_m == "-" or
override_f == "-" or override_n == "-" or override_p == "-" or
not short_accent and (not override_m or not override_f or
not override_n or not override_p)
if has_short then
insert_cat("~ with short forms")
if missing_short then
-- insert_cat("~ with missing short forms")
end
end
if short_accent then
-- insert_cat("~ with short accent pattern " .. (short_accent:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
-- insert_cat("~ with reducible short stem")
end
if rfind(orig_short_accent, "%(1%)") then
-- insert_cat("~ with Zaliznyak short form special case 1")
end
if rfind(orig_short_accent, "%(2%)") then
-- insert_cat("~ with Zaliznyak short form special case 2")
end
end
if short_stem and short_stem ~= args.stem then
insert_cat("~ with irregular short stem")
end
end
for _, case in ipairs(all_cases) do
if args[case] and args[case] ~= "-" then
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
short="short",
})
engcase = rsub(engcase, "(_[a-z]*)$", {
_m=" masculine singular", _f=" feminine singular",
_n=" neuter singular", _p=" plural",
_mp=" masculine plural"
})
-- insert_cat("~ with irregular " .. engcase)
end
end
if args.nofull then
-- insert_cat("short-form-only ~")
end
end
--------------------------------------------------------------------------
-- Autodetection and stem munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the base and the ending; also extract the accent type for short
-- adjectives and optional short stem. DECL is the value passed in, and
-- might already specify the ending. Return five values: STEM, STEMTR, DECL,
-- SHORT_ACCENT (accent class of short adjective, or nil for no short
-- adjectives other than specified through overrides), SHORT_STEM (special
-- stem of short adjective, nil if same as long stem). The return value of
-- SHORT_STEM is taken directly from the argument and will include any
-- manual translit.
detect_stem_and_accent_type = function(lemma, tr, decl, args)
local datedrare = false
-- If it looks like a short decl type, canonicalize. [abc] for types
-- a, b, c'', etc.; [d] for dated-*; [r] for rare-*;
-- [-] for - (no short forms); [*(] for * and (1) and (2) modifiers,
-- which might precede the letter.
if rfind(decl, "^[abcdr*(-]") then
decl = ":" .. decl
end
local splitvals = rsplit(decl, ":")
if #splitvals > 3 then
error("Should be at most three colon-separated parts of a declension spec: " .. decl)
end
local short_accent, short_stem
decl, short_accent, short_stem = splitvals[1], splitvals[2], splitvals[3]
-- Check for dated variant of short accent
local dated_short = short_accent and rmatch(short_accent, "^dated%-(.*)$")
if dated_short then
datedrare = "dated"
short_accent = dated_short
else
-- Check for rare variant of short accent
local rare_short = short_accent and rmatch(short_accent, "^rare%-(.*)$")
if rare_short then
datedrare = "rare"
short_accent = rare_short
end
end
decl = ine(decl)
-- Resolve aliases
if decl then
decl = rsub(decl, "^ъ%-", "")
end
if short_accent == "-" then
short_accent = nil
datedrare = "none"
end
short_accent = ine(short_accent)
short_stem = ine(short_stem)
if short_stem and not short_accent then
error("With explicit short stem " .. short_stem .. ", must specify short accent")
end
local base, ending
-- The while loop appears to function solely as a way of allowing a
-- jump to the end of the loop with a 'break' statement. I don't think
-- the loop is ever run more than once.
while true do
if not decl or decl == "ь" then
base, ending = rmatch(lemma, "^(.*)([ыиіое]́?й)$")
if base then
if ending == "ий" and decl == "ь" then
ending = "ьий"
elseif ending == "ій" and decl == "ь" then
ending = "ьій"
elseif ending == "е́й" or (ending == "ей" and com.is_monosyllabic(lemma)) then
ending = "ье́й"
end
tr = com.strip_tr_ending(tr, ending)
-- -ий/-ій will be converted to -ый after velars and sibilants
-- by the caller
decl = com.make_unstressed(ending)
break
else
-- It appears that short, mixed and proper adjectives are always
-- either of the -ов/ев/ёв or -ин/ын types. The former type is
-- always (or almost always?) short, while the latter can be
-- either; apparently mixed is the more "modern" type of
-- declension, and short is "older". However, both -ов/ев/ёв or
-- -ин/ын are of type "proper" (similar to "short") when
-- capitalized.
--
-- NOTE: Following regexp is accented
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]́н)ъ?$")
if base then
decl = "stressed-proper"
break
end
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[еёо]́?в)ъ?$")
if not base then
-- Following regexp is not stressed
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]н)ъ?$")
end
if base then
decl = "proper"
break
end
base = rmatch(lemma, "^(.*[еёо]́?в)ъ?$")
if base then
decl = "short"
break
end
base = rmatch(lemma, "(.*[иы]́н)ъ?$") --accented
if base then
decl = "stressed-short"
break
end
base = rmatch(lemma, "(.*[иы]н)ъ?$") --unaccented
if base then
decl = "mixed"
break
-- error("With -ин/ын adjectives, must specify 'short' or 'mixed':" .. lemma)
end
error("Cannot determine stem type of adjective: " .. lemma)
end
elseif m_table.contains({"short", "stressed-short", "mixed", "proper",
"stressed-proper"}, decl) then
base = rmatch(lemma, "^(.-)ъ?$")
assert(base)
break
elseif decl == "й" or decl == "й-short" then
base = rmatch(lemma, "^(.-)й$")
assert(base)
tr = com.strip_tr_ending(tr, "й")
decl = "й-short"
break
else
base = lemma
break
end
end
if not datedrare and (args.refl or not (decl == "ый" or decl == "ий" and not rfind(base, "[цс]к$"))) then
datedrare = "none"
end
return base, tr, decl, short_accent, short_stem, datedrare
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. бескра́йний with
-- dereduced nom sg бескра́ен without expected -ь.
local function add_bare_suffix(bare, baretr, old, decl, dereduced)
if decl == "й-short" then
return bare .. "й", baretr and baretr .. "j" or nil
elseif old and decl ~= "ій" and decl ~= "$" then
return bare .. "ъ", baretr
elseif decl == "ий" or decl == "ій" then
-- This next special case is mentioned in Zaliznyak's 1980 grammatical
-- dictionary for adjectives (footnote, p. 60).
if dereduced and rfind(bare, "[нН]$") then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "]́?$") then
-- This happens with adjectives like длинноше́ий, short masculine
-- singular длинноше́й.
return bare .. "й", baretr and baretr .. "j" or nil
else
return bare .. "ь", baretr and baretr .. "ʹ" or nil
end
else
return bare, baretr
end
end
-- Construct and set bare and short form in args, and canonicalize
-- short accent spec, handling cases *, (1) and (2). Return canonicalized
-- short accent and the short declension, which is usually the same as
-- the corresponding long one.
construct_bare_and_short_stem = function(args, short_accent, short_stem,
short_stemtr, accented_stem, accented_stemtr, old, decl)
-- Check if short forms allowed; if not, no short-form params can be given.
-- Construct bare version of stem; used for cases where the ending
-- is non-syllabic (i.e. short masculine singular of long adjectives,
-- and masculine singular of short, mixed and proper adjectives). Comes
-- from short masculine or 3rd argument if explicitly given, else from the
-- accented stem, possibly with the dereduction transformation applied
-- (if * occurs in the short accent spec).
local reducible, sc1, sc2
if short_accent then
short_accent, reducible = rsubb(short_accent, "%*", "")
short_accent, sc1 = rsubb(short_accent, "%(1%)", "")
short_accent, sc2 = rsubb(short_accent, "%(2%)", "")
end
if sc1 or sc2 then
-- Reducible isn't compatible with sc1 or sc2, but Zaliznyak's
-- dictionary always seems to notate sc1 and sc2 with reducible *,
-- so ignore it.
reducible = false
end
if sc1 and sc2 then
error("Special cases 1 and 2, i.e. (1) and (2), not compatible")
end
local short_decl = decl
-- Construct short stem. May be explicitly given, else comes from
-- end-accented stem.
if not short_stem then
short_stem, short_stemtr = accented_stem, accented_stemtr
end
-- Try to accent unaccented short stem (happens only when explicitly given),
-- but be conservative -- only if monosyllabic, since otherwise we have
-- no idea where stress should end up; after all, the explicit short stem
-- is for exceptional cases.
if not args.allow_unaccented then
if short_stemtr and com.is_unstressed(short_stem) ~= com.is_unstressed(short_stemtr) then
error("Explicit short stem " .. short_stem .. " and translit " .. short_stemtr .. " must have same accent pattern")
end
if com.is_monosyllabic(short_stem) then
short_stem, short_stemtr = com.make_ending_stressed(short_stem, short_stemtr)
elseif com.needs_accents(short_stem) then
error("Explicit short stem " .. short_stem .. " needs an accent")
end
end
if sc2 then
if not rfind(short_stem, "нн$") then
error("With special case 2, stem needs to end in -нн: " .. short_stem)
end
short_stem = rsub(short_stem, "нн$", "н")
if short_stemtr then
if not rfind(short_stemtr, "nn$") then
error("With special case 2, stem translit needs to end in -nn: " .. short_stemtr)
end
short_stemtr = rsub(short_stemtr, "nn$", "n")
end
end
-- Construct bare form, used for short masculine.
local bare, baretr
if reducible then
bare, baretr = com.dereduce_stem(short_stem, short_stemtr, rfind(short_accent, "^b"))
if not bare then
error("Unable to dereduce stem: " .. short_stem)
end
bare, baretr = add_bare_suffix(bare, baretr, old, decl, true)
else
bare, baretr = short_stem, short_stemtr
if sc1 then
if not rfind(bare, "нн$") then
error("With special case 1, stem needs to end in -нн: " .. bare)
end
bare = rsub(bare, "нн$", "н")
if baretr then
if not rfind(baretr, "nn$") then
error("With special case 1, stem translit needs to end in -nn: " .. baretr)
end
baretr = rsub(baretr, "nn$", "n")
end
end
-- With special case 1 or 2, we don't ever want -ь added, so treat
-- it like a reducible (that may be why these are marked as
-- reducible in Zaliznyak).
bare, baretr = add_bare_suffix(bare, baretr, old, decl, sc1 or sc2)
end
args.short_stem, args.short_stemtr = short_stem, short_stemtr
args.short_ustem, args.short_ustemtr = com.make_unstressed_once(short_stem, short_stemtr)
args.bare, args.baretr = bare, baretr
return short_accent, short_decl
end
--------------------------------------------------------------------------
-- Declensions --
--------------------------------------------------------------------------
declensions["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_p"] = "ые",
["gen_m"] = "ого",
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
declensions["ий"] = {
["nom_m"] = "ий",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_p"] = "ие",
["gen_m"] = "его",
["gen_f"] = "ей",
["gen_p"] = "их",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "им",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "им",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "ем",
["pre_f"] = "ей",
["pre_p"] = "их",
}
declensions["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_p"] = "ы́е",
["gen_m"] = "о́го",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
-- These can be stressed in ничья́ "draw, tie (in sports)".
declensions["ьий"] = {
["nom_m"] = "и́й",
["nom_n"] = "ье́",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ье́го",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ье́му",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ье́",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ье́м",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьём",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["short"] = {
["nom_m"] = "",
["nom_n"] = "о́",
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = "о́",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-short"] = mw.clone(declensions["short"])
declensions["stressed-short"]["pre_m"] = "е́"
declensions["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = "е́й",
["gen_p"] = "и́х",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́м",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́м",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ём",
["pre_f"] = "е́й",
["pre_p"] = "и́х",
}
declensions["mixed"] = {
["nom_m"] = "",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"ого", "а2"},
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = {"ому", "у2"},
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
internal_notes_table["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders["mixed"] = {"m"}
internal_notes_table_old["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders_old["mixed"] = {"m"}
declensions["proper"] = {
["nom_m"] = "",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "е́",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-proper"] = declensions["proper"]
for _, decl in ipairs({"proper", "stressed-proper"}) do
internal_notes_table[decl] = "<sup>1</sup> Rare."
internal_notes_table_old[decl] = "<sup>1</sup> Rare."
internal_notes_genders[decl] = {"f"}
internal_notes_genders_old[decl] = {"f"}
end
declensions["$"] = {
["nom_m"] = "",
["nom_n"] = "",
["nom_f"] = "",
["nom_p"] = "",
["gen_m"] = "",
["gen_f"] = "",
["gen_p"] = "",
["dat_m"] = "",
["dat_f"] = "",
["dat_p"] = "",
["acc_f"] = "",
-- don't do this; instead we default it to nom_n
-- ["acc_n"] = "",
["ins_m"] = "",
["ins_f"] = "",
["ins_p"] = "",
["pre_m"] = "",
["pre_f"] = "",
["pre_p"] = "",
-- for old-style templates, два, оба, compounds of два
["nom_mp"] = "",
["nom_fp"] = "",
["gen_mp"] = "",
["gen_fp"] = "",
["dat_mp"] = "",
["dat_fp"] = "",
-- don't do this; instead we default them to nom_mp, nom_fp
-- ["acc_mp"] = "",
-- ["acc_fp"] = "",
["ins_mp"] = "",
["ins_fp"] = "",
["pre_mp"] = "",
["pre_fp"] = "",
}
declensions_old["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_mp"] = "ые",
["nom_p"] = "ыя",
["gen_m"] = "аго",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["ій"] = {
["nom_m"] = "ій",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_mp"] = "іе",
["nom_p"] = "ія",
["gen_m"] = "яго",
["gen_f"] = "ей",
["gen_p"] = "ихъ",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "имъ",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "имъ",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "емъ",
["pre_f"] = "ей",
["pre_p"] = "ихъ",
}
declensions_old["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_mp"] = "ы́е",
["nom_p"] = "ы́я",
["gen_m"] = {"а́го", "о́го"},
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́мъ",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["ьій"] = {
["nom_m"] = "ій",
["nom_n"] = "ье",
["nom_f"] = "ья",
["nom_p"] = "ьи",
["gen_m"] = "ьяго",
["gen_f"] = "ьей",
["gen_p"] = "ьихъ",
["dat_m"] = "ьему",
["dat_f"] = "ьей",
["dat_p"] = "ьимъ",
["acc_f"] = "ью",
["acc_n"] = "ье",
["ins_m"] = "ьимъ",
["ins_f"] = {"ьей", "ьею"},
["ins_p"] = "ьими",
["pre_m"] = "ьемъ",
["pre_f"] = "ьей",
["pre_p"] = "ьихъ",
}
declensions_old["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́хъ",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́мъ",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́мъ",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьёмъ",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́хъ",
}
declensions_old["short"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = "а",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "у",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["stressed-short"] = mw.clone(declensions_old["short"])
declensions_old["stressed-short"]["pre_m"] = "ѣ́"
declensions_old["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = {"е́й", "ея́"},
["gen_p"] = "и́хъ",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́мъ",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́мъ",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ёмъ",
["pre_f"] = "е́й",
["pre_p"] = "и́хъ",
}
declensions_old["mixed"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"аго", "а1"},
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = {"ому", "у1"},
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["proper"] = {
["nom_m"] = "ъ",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "ѣ́",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["stressed-proper"] = declensions_old["proper"]
declensions_old["$"] = declensions["$"]
local function frob_genitive_masc(decl)
-- signal to combine_stem_and_suffix() to use the special tr_adj()
-- function so that -го gets transliterated to -vo
if type(decl["gen_m"]) == "table" then
local entries = {}
for _, entry in ipairs(decl["gen_m"]) do
table.insert(entries, rsub(entry, "го$", "го<adj>"))
end
decl["gen_m"] = entries
else
decl["gen_m"] = rsub(decl["gen_m"], "го$", "го<adj>")
end
end
-- Frob declensions, adding <adj> to gen_m forms ending in -го. This is
-- a signal to add manual translit early on that renders -го as -vo.
for _, decl in pairs(declensions_old) do
frob_genitive_masc(decl)
end
for _, decl in pairs(declensions) do
frob_genitive_masc(decl)
end
--------------------------------------------------------------------------
-- Declension functions --
--------------------------------------------------------------------------
local function attach_unstressed(args, suf, short)
local stem, stemtr
if short then
stem, stemtr = args.short_stem, args.short_stemtr
else
stem, stemtr = args.stem, args.stemtr
end
if suf == nil then
return nil
elseif nom.nonsyllabic_suffixes[suf] then
if not args.bare then
return nil
elseif rfind(args.bare, "[йьъ]$") then
return {args.bare, args.baretr}
elseif suf == "ъ" then
return com.concat_russian_tr(args.bare, args.baretr, suf, nil, "dopair")
else
return {args.bare, args.baretr}
end
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(stem, stemtr, suf, rules, args.old))
end
local function attach_stressed(args, suf, short)
local ustem, ustemtr
if short then
ustem, ustemtr = args.short_ustem, args.short_ustemtr
else
ustem, ustemtr = args.ustem, args.ustemtr
end
if suf == nil then
return nil
elseif not rfind(suf, "[ё́]") then -- if suf has no "ё" or accent marks
return attach_unstressed(args, suf, short)
end
local rules = nom.stressed_rules[ulower(usub(ustem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(ustem, ustemtr, suf, rules, args.old))
end
local function attach_both(args, suf, short)
local results = {}
-- Examples with stems with ё on Zaliznyak p. 61 list the
-- ending-stressed forms first, so go with that.
-- NOTE: This assumes we get one value returned, not a list of such values.
table.insert(results, attach_stressed(args, suf, short))
table.insert(results, attach_unstressed(args, suf, short))
return results
end
local function attach_with(args, suf, fun, short)
if type(suf) == "table" then
local all_combineds = {}
for _, x in ipairs(suf) do
local combineds = attach_with(args, x, fun, short)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
end
return all_combineds
else
local funval = fun(args, suf, short)
if funval then
local tbl = {}
assert(type(funval) == "table")
if type(funval[1]) ~= "table" then
funval = {funval}
end
for _, x in ipairs(funval) do
table.insert(tbl,
com.concat_paired_russian_tr(x, args.real_suffix))
end
return tbl
else
return {}
end
end
end
local function gen_form(args, decl, case, fun)
if not args.forms[case] then
args.forms[case] = {}
end
insert_forms_into_existing_forms(args.forms[case],
attach_with(args, decl[case], fun, false))
end
decline = function(args, decl, stressed)
local attacher = stressed and attach_stressed or attach_unstressed
for _, case in ipairs(long_cases) do
gen_form(args, decl, case, attacher)
end
end
canonicalize_override = function(args, case)
local val = args[case]
if not val then
return nil
end
val = rsplit(val, "%s*,%s*")
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(val) do
local ru, tr = com.split_russian_tr(v)
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
val = newvals
return val
end
handle_forms_and_overrides = function(args, short_forms_allowed)
local f = args.forms
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
for _, case in ipairs(long_cases) do
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
args[case] = canonicalize_override(args, case) or f[case]
end
for _, case in ipairs(short_cases) do
if short_forms_allowed then
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
if args.shorttailall then
append_note_all(case, args.shorttailall)
end
if args.shorttail then
append_note_last(case, args.shorttail, ">1")
end
args[case] = canonicalize_override(args, case) or f[case]
else
args[case] = nil
end
end
-- Convert an empty list to nil, so that an mdash is inserted. This happens,
-- for example, with words like голубой where args.bare is set to nil.
for _, case in ipairs(all_cases) do
if args[case] and #args[case] == 0 then
args[case] = nil
end
end
-- default acc_n to nom_n; applies chiefly in the indeclinable declension
-- (used with manual declension tables)
if not args.acc_n then
args.acc_n = args.nom_n
end
-- default inanimate/animate accusative variants as appropriate; this is
-- almost always correct, but not with e.g. два́дцать оди́н, where the
-- masculine animate accusative два́дцать одного́ differs from both the
-- masculine nominative два́дцать оди́н and the masculine genitive
-- двадцати́ одного́.
if not args.acc_m_an then
args.acc_m_an = args.gen_m
end
if not args.acc_m_in then
args.acc_m_in = args.nom_m
end
-- Compounds of два do not have animacy; everything else does.
-- Only copy either the with-animacy or without-animacy variants to avoid
-- having both forms in {{ru-generate-adj-forms}}.
if args.special ~= "cdva" then
if not args.acc_p_an then
args.acc_p_an = args.gen_p
end
if not args.acc_p_in then
args.acc_p_in = args.nom_p
end
if not args.acc_mp_an then
args.acc_mp_an = args.gen_mp
end
if not args.acc_mp_in then
args.acc_mp_in = args.nom_mp
end
if not args.acc_fp_an then
args.acc_fp_an = args.gen_fp
end
if not args.acc_fp_in then
args.acc_fp_in = args.nom_fp
end
else
if not args.acc_mp then
args.acc_mp = args.nom_mp
end
if not args.acc_fp then
args.acc_fp = args.nom_fp
end
end
end
--------------------------------------------------------------------------
-- Short adjective declension --
--------------------------------------------------------------------------
short_declensions["ый"] = { m="", f="а́", n="о́", p="ы́" }
short_declensions["ой"] = short_declensions["ый"]
short_declensions["ий"] = { m="ь", f="я́", n="е́", p="и́" }
short_declensions_old["ый"] = { m="ъ", f="а́", n="о́", p="ы́" }
short_declensions_old["ой"] = short_declensions_old["ый"]
short_declensions_old["ій"] = short_declensions["ий"]
-- Short adjective stress patterns:
-- "-" = stem-stressed
-- "+" = ending-stressed (drawn onto the last syllable of stem in masculine)
-- "-+" = both possibilities
short_stress_patterns["a"] = { m="-", f="-", n="-", p="-" }
short_stress_patterns["a'"] = { m="-", f="-+", n="-", p="-" }
short_stress_patterns["b"] = { m="+", f="+", n="+", p="+" }
short_stress_patterns["b'"] = { m="+", f="+", n="+", p="-+" }
short_stress_patterns["c"] = { m="-", f="+", n="-", p="-" }
short_stress_patterns["c'"] = { m="-", f="+", n="-", p="-+" }
short_stress_patterns["c''"] = { m="-", f="+", n="-+", p="-+" }
local function gen_short_form(args, decl, case, fun, datedrare)
if not args.forms["short_" .. case] then
args.forms["short_" .. case] = {}
end
local inserted = insert_forms_into_existing_forms(
args.forms["short_" .. case], attach_with(args, decl[case], fun, true),
(datedrare == "dated" and datedrare == "rare") and "*" or nil)
if datedrare == "dated" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Dated.")
elseif datedrare == "rare" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Rare.")
end
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
["-+"] = attach_both,
}
decline_short = function(args, decl, stress_pattern, dated)
if stress_pattern then
for _, case in ipairs({"m", "f", "n", "p"}) do
gen_short_form(args, decl, case, attachers[stress_pattern[case]],
dated)
end
end
end
--------------------------------------------------------------------------
-- Create the table --
--------------------------------------------------------------------------
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local old_title_temp = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local title_temp_no_short_msg = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local old_title_temp_no_short_msg = [=[Pre-reform declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]
local template = nil
local full_clause = nil
local template_no_neuter = nil
local full_clause_no_neuter = nil
local surname_full_clause = nil
local template_mp = nil
local full_clause_mp = nil
local template_mp_no_neuter = nil
local full_clause_mp_no_neuter = nil
local surname_full_clause_mp = nil
local template_dva = nil
local full_clause_dva = nil
local full_clause_compound_dva = nil
local template_oba = nil
local full_clause_oba = nil
local short_clause_separator = nil
local short_clause = nil
local short_clause_no_neuter_separator = nil
local short_clause_no_neuter = nil
local short_clause_mp_separator = nil
local short_clause_mp = nil
local short_clause_mp_no_neuter_separator = nil
local short_clause_mp_no_neuter = nil
local internal_notes_template = nil
local notes_template = nil
local function get_accel_forms(old, special, has_nom_mp)
return {
-- used with all variants
nom_m = "nom|m|s",
nom_f = "nom|f|s",
nom_n = "nom|n|s",
-- not used with special; applies to all genders normally but only
-- feminine and neuter with old=1
nom_p = old and has_nom_mp and "nom|f//n|p" or "nom|p",
-- only used with old=1 or special; applies to the masculine and neuter if
-- special, but only masculine if old=1
nom_mp = special and "nom|m//n|p" or "nom|m|p",
-- only used with special
nom_fp = "nom|f|p",
-- the remaining singulars and non-gendered plurals used with all variants
-- except special == "oba"
gen_m = "gen|m//n|s",
gen_f = "gen|f|s",
gen_p = "gen|p",
dat_m = "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",
-- the following two not used with special in ("dva", "oba"); applies to
-- all genders normally but only feminine and neuter with old=1
acc_p_an = old and has_nom_mp and "an|acc|f//n|p" or "an|acc|p",
acc_p_in = old and has_nom_mp and "in|acc|f//n|p" or "in|acc|p",
-- the following two only used with old=1 or special in ("dva|oba");
-- applies to the masculine and neuter if special, but only masculine if
-- old=1
acc_mp_an = special and "an|acc|m//n|p" or "an|acc|m|p",
acc_mp_in = special and "in|acc|m//n|p" or "in|acc|m|p",
-- the following two only used with special in ("dva", "oba")
acc_fp_an = "an|acc|f|p",
acc_fp_in = "in|acc|f|p",
-- the next 6 are used with all variants except special == "oba"
ins_m = "ins|m//n|s",
ins_f = "ins|f|s",
ins_p = "ins|p",
pre_m = "pre|m//n|s",
pre_f = "pre|f|s",
pre_p = "pre|p",
-- the following two gendered plurals are only used with special == "cdva"
acc_mp = "acc|m//n|p",
acc_fp = "acc|f|p",
-- the remaining gendered plurals are only used with special == "oba"
gen_mp = "gen|m//n|p",
gen_fp = "gen|f|p",
dat_mp = "dat|m//n|p",
dat_fp = "dat|f|p",
ins_mp = "ins|m//n|p",
ins_fp = "ins|f|p",
pre_mp = "pre|m//n|p",
pre_fp = "pre|f|p",
-- short forms
short_m = "short|m|s",
short_f = "short|f|s",
short_n = "short|n|s",
short_p = "short|p",
}
end
-- Make the table
make_table = function(args)
local lemma_forms = args.special and args.nom_mp or
args.nofull and args.short_m or args.nom_m
args.lemma = m_links.remove_links(nom.show_form(lemma_forms, true, nil, nil))
args.title = args.title or strutils.format(
(args.special or args.manual) and args.old and old_title_temp_no_short_msg or
(args.special or args.manual) and title_temp_no_short_msg or
args.old and old_title_temp or
title_temp,
args)
local has_nom_mp = args.nom_mp and not (#args.nom_mp == 1 and args.nom_mp[1][1] == "-")
local accel_forms = get_accel_forms(args.old, args.special, has_nom_mp)
for _, case in ipairs(all_cases) do
if args[case] then
local accel_form = accel_forms[case]
if not accel_form then
error("Internal error: Unrecognized case " .. case .. " when looking up accelerator form")
end
if args.noneuter or args.real_surname then
accel_form = rsub(accel_form, "//n", "")
end
if args.real_surname then
accel_form = rsub(accel_form, "an|", "")
end
args[case] = nom.show_form(args[case], false, accel_form, lemma_forms)
else
args[case] = nil
end
end
local temp, fullc
if args.special == "oba" then
temp = template_oba
fullc = full_clause_oba
elseif args.special == "dva" then
temp = template_dva
fullc = full_clause_dva
elseif args.special == "cdva" then
temp = template_dva -- no template_cdva
fullc = full_clause_compound_dva
elseif args.real_surname and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = surname_full_clause_mp
elseif args.real_surname then
temp = template_no_neuter
fullc = surname_full_clause
elseif args.noneuter and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = full_clause_mp_no_neuter
elseif args.noneuter then
temp = template_no_neuter
fullc = full_clause_no_neuter
elseif args.old and has_nom_mp then
temp = template_mp
fullc = full_clause_mp
else
temp = template
fullc = full_clause
end
if args.old then
if has_nom_mp then
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_mp_no_neuter_separator or short_clause_mp_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_mp_no_neuter or short_clause_mp, args)
else
args.short_clause = ""
end
else
args.short_clause = ""
end
else
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_no_neuter_separator or short_clause_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_no_neuter or short_clause, args)
else
args.short_clause = ""
end
end
if not args.nofull then
args.full_clause = strutils.format(fullc, args)
else
args.full_clause = ""
end
args.internal_notes = table.concat(args.internal_notes, "<br />")
args.internal_notes_clause = #args.internal_notes > 0 and strutils.format(internal_notes_template, args) or ""
args.notes_clause = args.notes and strutils.format(notes_template, args) or ""
return strutils.format(temp, args)
end
-- Used for new-style templates
short_clause_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for new-style templates
short_clause = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for new-style templates
short_clause_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=5 |
|-
]===]
-- Used for new-style templates
short_clause_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=7 |
|-
]===]
-- Used for old-style templates
short_clause_mp = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for old-style templates
short_clause_mp_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for both new-style and old-style templates
notes_template = [===[
<div style="width:100%;text-align:left">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
-- Used for both new-style and old-style templates
internal_notes_template = rsub(notes_template, "notes", "internal_notes")
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue)">{title}</div>
<div class="NavContent">
{\op}| style="background:var(--wikt-palette-paleblue);text-align:center" class="inflection-table"
|-
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[{full_clause}|-{short_clause}
|{\cl}{internal_notes_clause}{notes_clause}</div></div></div>]===]
end
-- Used for both new-style and old-style templates
template = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
template_no_neuter = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
surname_full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for old-style templates
template_mp = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်/ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for old-style templates
template_mp_no_neuter = template_prelude("60") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for some old-style templates
surname_full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for два and compounds
template_dva = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်/နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of два (only for два itself,
-- which has an animacy distinction; not for compounds)
full_clause_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for both new-style and old-style templates of compounds of два
full_clause_compound_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=4 | {acc_mp}
| data-accel-col=5 | {acc_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for оба
template_oba = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်နပုလ္လိၚ်/ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of оба
full_clause_oba = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_mp}
| data-accel-col=5 | {gen_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_mp}
| data-accel-col=5 | {dat_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_mp_an}
| data-accel-col=5 | {acc_fp_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_mp}
| data-accel-col=5 | {ins_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_mp}
| data-accel-col=5 | {pre_fp}
]===]
return export
gadn5l4un1u6jw8a1jl9vrf8g9thnc7
399873
399865
2026-07-23T01:03:42Z
Intobesa.bot
1035
Bot: ပွမကၠာဲစုတ်ယၟုနူဘာသာအၚ်္ဂလိက်
399873
Scribunto
text/plain
--[=[
This module contains functions for creating inflection tables for Russian
adjectives.
Author: Benwing, rewritten from early version by Wikitiki89
Arguments:
1: lemma; nom sg, or just the stem if an explicit declension type is
given in arg 2
2: declension type (usually omitted to autodetect based on the lemma),
along with any short accent type and optional irregular short stem;
see below.
CASE_NUMGEN: Override a given form; see abbreviations below
suffix: any suffix to attach unchanged to the end of each form
notes: Notes to add to the end of the table
title: Override the title
shorttail: Footnote (e.g. *, 1, 2, etc.) to add to short forms if
there's more than one; automatically superscripted
shorttailall: Same as shorttail= but applies to all short forms even
if there's only one
CASE_NUMGEN_tail: Like shorttailall but only for a specific form
nofull: Short forms only
Case abbreviations:
nom: nominative
gen: genitive
dat: dative
acc: accusative
ins: instrumental
pre: prepositional
short: short form
Number/gender abbreviations:
m: masculine singular
n: neuter singular
f: feminine singular
p: plural
mp: masculine plural (old-style and special numeral tables only)
fp: masculine plural (special numeral tables only)
Animacy abbreviations:
an: animate
in: inanimate
Declension-type argument (arg 2):
Form is DECLSPEC or DECLSPEC,DECLSPEC,... where DECLSPEC is
one of the following:
DECLTYPE:SHORTACCENT:SHORTSTEM
DECLTYPE:SHORTACCENT
DECLTYPE
SHORTACCENT:SHORTSTEM
SHORTACCENT
(blank)
DECLTYPE should normally be omitted, and the declension autodetected
from the ending; or it should be ь, to indicate that an adjective
in -ий is of the possessive variety with an extra -ь- in most of
the endings. Alternatively, it can be an explicit declension type,
in which case the lemma field needs to be replaced with the bare
stem; the following are the possibilities:
ый ий ой ьий short mixed manual (new-style)
ый ій ьій short stressed-short mixed proper stressed-proper
ъ-short ъ-stressed-short ъ-mixed ъ-proper ъ-stressed-proper
manual (old-style, where ъ-* is a synonym for *, for any *)
SHORTACCENT is one of a a' b b' c c' c'' to auto-generate the
short forms with the specified accent pattern (following
Zaliznyak); if omitted, no short forms will be auto-generated.
SHORTACCENT can contain a * in it for "reducible" adjectives,
where the short masculine singular has an epenthetic vowel
in the final syllable. It can also contain (1) or (2) to
indicate special cases. Both are used in conjunction with
adjectives in -нный/-нний. Special case (1) causes the
short masculine singular to end in -н instead of -нн; special
case (2) causes all short forms to end this way.
SHORTSTEM, if present, is used as the short stem to base the
short forms off of, instead of the normal adjective long stem
(possibly with a final-syllable accent added in the case of
declension type -о́й).
TODO:
1. Figure out what the symbol X-inside-square (⊠) means, which seems to go with
all adjectives in -о́й with multi-syllabic stems. It may mean that the
masculine singular short form is missing. If this indeed a regular thing,
we need to implement it (and if it's regular but means something else,
we need to implement that, too). Also figure out what the other signs
on pages 68-76 etc. mean: -, X, ~, П₂, Р₂, diamond (♢), triangle (△; might
simply mean a misc. irregularity; explained on p. 61).
2. Mark irregular overridden forms with △ (esp. appropriate for short forms).
3. Should non-reducible adjectives in -нный and -нний default to special case
(1)?
4. In the case of a non-dereducible short masc sing of stress type b, we don't
currently move the stress to the last syllable. Should we?
5. FIXME: In decline(), we used to default acc_n to nom_n. Now we do that in
handle_forms_and_overrides(). Verify that this is more correct.
6. FIXME: Allow multiple heads, both to handle cases where two manual translits
exist (or rather, one automatic and one manual), and cases where two
stresses are possible, e.g. мину́вший or ми́нувший.
7. FIXME: Add code to generate the regular comparative. The rules are as
follows: If the stem doesn't end in к г х, add -ee with no stress change
if the short form is type a, else add -е́е (including type a'). If the stem
ends in к г х, turn the last consonant into ч ж ш, add -е, and place the
stress on the syllable preceding the ending. (E.g. дорого́й -> доро́же)
]=]--
local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_table = require("Module:table")
local com = require("Module:ru-common")
local nom = require("Module:ru-nominal")
local strutils = require("Module:string utilities")
local m_table_tools = require("Module:table tools")
local m_debug = require("Module:debug")
local export = {}
local lang = require("Module:languages").getByCode("ru")
----------------------------- Utility functions ------------------------
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local usub = mw.ustring.sub
-- 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
-- Insert a single form (consisting of {RUSSIAN, TR}) or a list of such
-- forms into an existing list of such forms, adding NOTESYM (a string or nil)
-- to the new forms if not nil. Return whether an insertion was performed.
local function insert_forms_into_existing_forms(existing, newforms, notesym)
if type(newforms) ~= "table" then
newforms = {newforms}
end
local inserted = false
for _, item in ipairs(newforms) do
if not m_table.contains(existing, item) then
if notesym then
item = com.concat_paired_russian_tr(item, {notesym})
end
table.insert(existing, item)
inserted = true
end
end
return inserted
end
local function track(page)
m_debug.track("ru-adjective/" .. page)
return true
end
-- Fancy version of ine() (if-not-empty). Converts empty string to nil,
-- but also strips leading/trailing space and then single or double quotes,
-- to allow for embedded spaces.
local function ine(arg)
if not arg then return nil end
arg = rsub(arg, "^%s*(.-)%s*$", "%1")
if arg == "" then return nil end
local inside_quotes = rmatch(arg, '^"(.*)"$')
if inside_quotes then
return inside_quotes
end
inside_quotes = rmatch(arg, "^'(.*)'$")
if inside_quotes then
return inside_quotes
end
return arg
end
-------------------- Global declension/case/etc. variables -------------------
-- 'enable_categories' is a special hack for testing, which disables all
-- category insertion if false. Delete this as soon as we've verified the
-- working of the category code and created all the necessary categories.
local enable_categories = true
local declensions = {}
local declensions_old = {}
local internal_notes_table = {}
local internal_notes_table_old = {}
local internal_notes_genders = {}
local internal_notes_genders_old = {}
local short_declensions = {}
local short_declensions_old = {}
-- Formerly used for the ой-rare type, which has been removed; but keep
-- the code around in case we need it later.
local short_internal_notes_table = {}
local short_internal_notes_table_old = {}
local short_stress_patterns = {}
local long_cases = {
"nom_m", "nom_n", "nom_f", "nom_p",
"gen_m", "gen_f", "gen_p",
"dat_m", "dat_f", "dat_p",
"acc_m_an", "acc_m_in", "acc_p_an", "acc_p_in", "acc_f", "acc_n",
"ins_m", "ins_f", "ins_p",
"pre_m", "pre_f", "pre_p",
-- extra old long cases
"nom_mp",
"acc_mp_an", "acc_mp_in",
-- extra dva cases
"nom_fp",
"acc_fp_an", "acc_fp_in",
-- extra oba cases
"gen_mp", "gen_fp",
"dat_mp", "dat_fp",
"ins_mp", "ins_fp",
"pre_mp", "pre_fp",
-- extra cases for compounds of два
"acc_mp", "acc_fp",
}
-- Short cases and corresponding numbered arguments
local short_cases = {
"short_m", "short_n", "short_f", "short_p"
}
-- Create master list of all possible cases (actually case/number/gender pairs)
local all_cases = mw.clone(long_cases)
for _, case in ipairs(short_cases) do
m_table.insertIfNot(all_cases, case)
end
-- If enabled, compare this module with new version of module to make
-- sure all declensions are the same.
local test_new_ru_adjective_module = false
-- Forward references to functions
local tracking_code
local categorize
local detect_stem_and_accent_type
local construct_bare_and_short_stem
local decline
local canonicalize_override
local handle_forms_and_overrides
local decline_short
local make_table
--------------------------------------------------------------------------
-- Main code --
--------------------------------------------------------------------------
-- Implementation of main entry point
function export.do_generate_forms(args, old, manual)
local orig_args
if test_new_ru_adjective_module then
orig_args = mw.clone(args)
end
if args[3] or args[4] or args[5] or args[6] then
error("Numbered short forms no longer supported")
end
if args.shorttailall then
track("shorttailall")
end
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
args.forms = {}
args.categories = {}
old = old or args.old
args.old = old
args.suffix = com.split_russian_tr(args.suffix or "", "dopair")
args.internal_notes = {}
-- Superscript footnote marker at beginning of note, similarly to what's
-- done at end of forms.
if args.notes then
local notes, entry = m_table_tools.get_initial_notes(args.notes)
args.notes = notes .. entry
end
local overall_short_forms_allowed
manual = manual or args[2] == "manual"
args.manual = manual
local decl_types = manual and "$" or args[2] or ""
local lemmas = manual and "-" or args[1] or SUBPAGENAME
local normal_short_classes, rare_short_classes, dated_short_classes
local saw_no_short
for _, lemma_and_tr in ipairs(rsplit(lemmas, ",")) do
-- reset these for each lemma so we get the short classes of the last
-- lemma (doesn't really matter, as they should be the same for all
-- lemmas)
normal_short_classes = {}
rare_short_classes = {}
dated_short_classes = {}
saw_no_short = false
for _, decl_type in ipairs(rsplit(decl_types, ",")) do
local lemma, lemmatr = com.split_russian_tr(lemma_and_tr)
-- if lemma ends with -ся, strip it and act as if suffix=ся given
-- (or rather, prepend ся to suffix)
local active_base = rmatch(lemma, "^(.*)ся$")
if active_base then
lemma = active_base
lemmatr = com.strip_tr_ending(lemmatr, "ся")
args.refl = true
args.real_suffix = com.concat_paired_russian_tr({"ся"}, args.suffix)
else
args.refl = false
args.real_suffix = args.suffix
end
-- Auto-detect actual decl type, and get short accent and overriding
-- short stem, if specified.
local stem, stemtr, short_accent, short_stem, short_stemtr, datedrare
stem, stemtr, decl_type, short_accent, short_stem, datedrare =
detect_stem_and_accent_type(lemma, lemmatr, decl_type, args)
if rfind(decl_type, "^[іи]й$") and rfind(stem, "[" .. com.velar .. com.sib .. "]$") then
decl_type = "ый"
end
if datedrare == "none" then
saw_no_short = true
end
local proper_decl = m_table.contains({"proper", "stressed-proper"}, decl_type)
-- Use args.real_surname to avoid overwriting args.surname, since we may be overwriting
-- `args` multiple times. FIXME: Use a separate data structure for this.
args.real_surname = proper_decl or args.surname
local short_title
if short_accent then
short_title = short_accent
elseif args.real_surname then
short_title = "surname"
elseif m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed"}, decl_type) then
short_title = "possessive"
end
if short_title then
if datedrare == "dated" then
m_table.insertIfNot(dated_short_classes, short_title)
elseif datedrare == "rare" then
m_table.insertIfNot(rare_short_classes, short_title)
else
m_table.insertIfNot(normal_short_classes, short_title)
end
end
if short_stem then
short_stem, short_stemtr = com.split_russian_tr(short_stem)
end
stem, args.allow_unaccented = rsubb(stem, "^%*", "")
if args.allow_unaccented then
track("allow-unaccented")
end
-- Treat suffixes without an accent, and suffixes with an accent on
-- the initial hyphen, as if they were preceded with a *, which
-- overrides all the logic that normally (a) normalizes the accent,
-- and (b) complains about multisyllabic words without an accent.
-- Don't do this if lemma is just -, which is used specially in
-- manual declension tables.
if lemma ~= "-" and (rfind(lemma, "^%-́") or (com.is_unstressed(lemma) and rfind(lemma, "^%-"))) then
args.allow_unaccented = true
end
if not args.allow_unaccented and com.needs_accents(lemma) then
-- Technically we don't need accents in -ой adjectives (which are
-- always ending-stressed) and in -ый adjectives with a monosyllabic
-- stem, such as полный (which are always stem-stressed), but it's
-- better to enforce accents in all multisyllabic words, for
-- consistency with nouns and verbs. Note that we still don't
-- require an accent in monosyllabic adjectives such as злой.
error("Lemma must have an accent in it: " .. lemma)
end
-- Set stem and unstressed version. Also construct end-accented version
-- of stem if unstressed; needed for short forms of adjectives of
-- type -о́й. We do this here before doing the dereduction
-- transformation so that we don't end up stressing an unstressed
-- epenthetic vowel, and so that the previous syllable instead ends
-- up stressed (in type -о́й adjectives the stem won't have any stress).
-- Note that the closest equivalent in nouns is handled in
-- attach_unstressed(), which puts the stress onto the final syllable
-- if the stress pattern calls for ending stress in the genitive
-- plural. This works there because
-- (1) It won't stress an unstressed epenthetic vowel because the
-- cases where the epenthetic vowel is unstressed are precisely
-- those with stem stress in the gen pl, not ending stress;
-- (2) There isn't a need to stress the syllable preceding an
-- unstressed epenthetic vowel because that syllable should
-- already have stress, since we require that the base stem form
-- (parameter 2) have stress in it whenever any case form has
-- stem stress. This isn't the case here in type -о́й adjectives.
-- NOTE: FIXME: I can't actually quote any forms from Zaliznyak
-- (at least not from pages 58-60, where this is discussed) that
-- seem to require last-stem-syllable-stress, i.e. where the stem is
-- multisyllabic. The two examples given are both unusual: дорого́й
-- has stress on the initial syllable до́рог etc. and these forms are
-- marked with a triangle (indicating an apparent irregularity); and
-- голубо́й seems not to have a masculine singular short form, and it's
-- accent pattern b, so the remaining forms are all ending-stressed.
-- In fact it's possible that these examples don't exist: It appears
-- that all the multisyllabic adjectives in -о́й listed in the
-- dictionary have a marking next to them consisting of an X inside of
-- a square, which is glossed p. 69 to something I don't understand,
-- but may be saying that the masculine singular short form is
-- missing. If this is regular, we need to implement it.
args.stem, args.stemtr = stem, stemtr
args.ustem, args.ustemtr = com.make_unstressed_once(stem, stemtr)
local accented_stem, accented_stemtr = stem, stemtr
if not args.allow_unaccented then
if accented_stemtr and com.is_unstressed(accented_stem) ~= com.is_unstressed(accented_stemtr) then
error("Stem " .. accented_stem .. " and translit " .. accented_stemtr .. " must have same accent pattern")
end
if com.is_unstressed(accented_stem) then
accented_stem, accented_stemtr =
com.make_ending_stressed(accented_stem, accented_stemtr)
end
end
local short_forms_allowed = manual and true or decl_type == "ый" or
decl_type == "ой" or decl_type == (old and "ій" or "ий")
overall_short_forms_allowed = overall_short_forms_allowed or
short_forms_allowed
if not short_forms_allowed then
-- FIXME: We might want to allow this in case we have a
-- reducible short, mixed or proper possessive adjective. But
-- in that case we need to reduce rather than dereduce to get
-- the stem.
if short_accent or short_stem then
error("Cannot specify short accent or short stem with declension type " .. decl_type .. ", as short forms aren't allowed")
end
if args.short_m or args.short_f or args.short_n or args.short_p then
error("Cannot specify explicit short forms with declension type " .. decl_type .. ", as short forms aren't allowed")
end
end
local orig_short_accent = short_accent
local short_decl_type
short_accent, short_decl_type = construct_bare_and_short_stem(args,
short_accent, short_stem, short_stemtr, accented_stem,
accented_stemtr, old, decl_type)
local decls = old and declensions_old or declensions
local short_decls = old and short_declensions_old or short_declensions
if not decls[decl_type] then
error("Unrecognized declension type " .. decl_type)
end
if short_accent == "" then
error("Short accent type cannot be blank, should be omitted or given")
end
if short_accent and not short_stress_patterns[short_accent] then
error("Unrecognized short accent type " .. short_accent)
end
tracking_code(decl_type, args, orig_short_accent, short_accent,
short_stem, datedrare, short_forms_allowed)
if not manual and enable_categories then
categorize(decl_type, args, orig_short_accent, short_accent,
short_stem)
end
decline(args, decls[decl_type], m_table.contains({"ой", "ьей", "й-short", "stressed-short", "stressed-proper"}, decl_type))
if short_forms_allowed and short_accent then
decline_short(args, short_decls[short_decl_type],
short_stress_patterns[short_accent], datedrare)
end
local intable = old and internal_notes_table_old or internal_notes_table
local shortintab = old and short_internal_notes_table_old or
short_internal_notes_table
local internal_note = intable[decl_type] or shortintab[short_decl_type]
if internal_note then
m_table.insertIfNot(args.internal_notes, internal_note)
end
end
end
local short_class_titles = {}
local function make_short_class_title(short_classes, datedrare)
local sct = table.concat(short_classes, ",") -- short class title
if sct == "" then
return
end
if not m_table.contains({"surname", "possessive"}, sct) then
-- Convert e.g. a*,a(1) into a*[(1)], either finally or followed by
-- comma.
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%))$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*,%1%*?(%([12]%)),", "%1*[%2],")
-- Same for a(1),a*.
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*$", "%1*[%2]")
sct = rsub(sct, "([abc]'*)%*?(%([12]%)),%1%*,", "%1*[%2],")
-- Convert (1), (2) to ①, ②.
sct = rsub(sct, "%(1%)", "①")
sct = rsub(sct, "%(2%)", "②")
-- Add a * before ①, ②, consistent with Zaliznyak.
sct = rsub(sct, "([abc]'*)([①②])", "%1*%2")
-- Convert ' and '' to ʹ and ʺ, consistent with Zaliznyak.
sct = sct:gsub("''", "ʺ"):gsub("'", "ʹ")
if args.nofull then
sct = "short-form-only class " .. sct
else
sct = "short class " .. sct
end
end
if datedrare then
sct = datedrare .. " " .. sct
end
table.insert(short_class_titles, sct)
end
make_short_class_title(normal_short_classes, nil)
make_short_class_title(rare_short_classes, "rare")
make_short_class_title(dated_short_classes, "dated")
if #short_class_titles == 0 then
if saw_no_short then
args.short_class_title = "no short forms"
else
args.short_class_title = "unknown short forms"
end
else
args.short_class_title = table.concat(short_class_titles, " / ")
end
handle_forms_and_overrides(args, overall_short_forms_allowed)
-- Test code to compare existing module to new one.
if test_new_ru_adjective_module then
local m_new_ru_adjective = require("Module:User:Benwing2/ru-adjective")
local newargs = m_new_ru_adjective.do_generate_forms(orig_args, old, manual)
local difdecl = false
for _, case in ipairs(all_cases) do
local arg = args[case]
local newarg = newargs[case]
if not m_table.deepEquals(arg, newarg) then
-- Uncomment this to display the particular case and
-- differing forms.
--error(case .. " " .. (arg and com.concat_forms(arg) or "nil") .. " || " .. (newarg and com.concat_forms(newarg) or "nil"))
track("different-decl")
difdecl = true
end
break
end
if not difdecl then
track("same-decl")
end
end
return args
end
local function process_params(frame, include_form)
local boolean = {type = "boolean"}
local params = {
[1] = true,
[2] = true,
suffix = true,
title = true,
special = true,
shorttail = true,
shorttailall = true,
notes = true,
old = boolean,
noneuter = boolean,
nofull = boolean,
surname = boolean,
pronoun = boolean
}
if include_form then
params.form = {required = true}
end
for _, case in ipairs(all_cases) do
params[case] = true
params[case .. "_tail"] = true
params[case .. "_tailall"] = true
end
return require("Module:parameters").process(frame:getParent().args, params)
end
-- Implementation of main entry point
local function do_show(frame, old, manual)
local args = export.do_generate_forms(process_params(frame), old, manual)
return make_table(args) .. m_utilities.format_categories(args.categories, lang)
end
-- The main entry point for modern declension tables.
function export.show(frame)
return do_show(frame, false)
end
-- The main entry point for old declension tables.
function export.show_old(frame)
return do_show(frame, true)
end
-- The main entry point for manual declension tables.
function export.show_manual(frame)
return do_show(frame, false, "manual")
end
-- The main entry point for manual old declension tables.
function export.show_manual_old(frame)
return do_show(frame, true, "manual")
end
-- Entry point for use in Module:ru-noun.
function export.get_nominal_decl(decl, gender, old)
local d = old and declensions_old[decl] or declensions[decl]
local n = {}
if gender == "m" then
n.nom_sg = d.nom_m
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
elseif gender == "f" then
n.nom_sg = d.nom_f
n.gen_sg = d.gen_f
n.dat_sg = d.dat_f
n.acc_sg = d.acc_f
n.ins_sg = d.ins_f
n.pre_sg = d.pre_f
elseif gender == "n" then
n.nom_sg = d.nom_n
n.gen_sg = d.gen_m
n.dat_sg = d.dat_m
n.acc_sg = d.acc_n
n.ins_sg = d.ins_m
n.pre_sg = d.pre_m
else
assert(false, "Unrecognized gender: " .. gender)
end
n.nom_pl = d.nom_p
n.gen_pl = d.gen_p
n.dat_pl = d.dat_p
n.ins_pl = d.ins_p
n.pre_pl = d.pre_p
if gender == "m" and d.nom_mp then
n.nom_pl = d.nom_mp
end
local intable = old and internal_notes_table_old or internal_notes_table
local ingenders = old and internal_notes_genders_old or internal_notes_genders
-- FIXME, what if there are multiple internal notes? See comment in
-- do_generate_forms().
local internal_notes = ingenders[decl] and m_table.contains(ingenders[decl], gender) and intable[decl]
return n, internal_notes
end
local function get_form(forms)
local canon_forms = {}
for _, form in ipairs(forms) do
local ru, tr = form[1], form[2]
local ruentry = m_table_tools.get_notes(ru)
local trentry, trnotes
if tr then
trentry, trnotes = m_table_tools.get_notes(tr)
end
ruentry = m_links.remove_links(ruentry)
m_table.insertIfNot(canon_forms, {ruentry, trentry})
end
return com.concat_forms(canon_forms)
end
-- The entry point for 'ru-adj-forms' to generate all adjective forms.
function export.generate_forms(frame)
local args = export.do_generate_forms(process_params(frame), false)
local ins_text = {}
for _, case in ipairs(all_cases) do
if args[case] then
table.insert(ins_text, case .. "=" .. get_form(args[case]))
end
end
return table.concat(ins_text, "|")
end
-- The entry point for 'ru-adj-form' to generate a particular adjective form.
function export.generate_form(frame)
local args = process_params(frame, "include form")
local form = args.form
if not m_table.contains(all_cases, form) then
error("Unrecognized form " .. form)
end
args = export.do_generate_forms(args, false)
if not args[form] then
return ""
else
return get_form(args[form])
end
end
--------------------------------------------------------------------------
-- Tracking and categorization --
--------------------------------------------------------------------------
tracking_code = function(decl_class, args, orig_short_accent, short_accent,
short_stem, datedrare)
local hint_types = com.get_stem_trailing_letter_type(args.stem)
local function dotrack(prefix)
if prefix ~= "" then
track(prefix)
prefix = prefix .. "/"
end
track(prefix .. decl_class)
for _, hint_type in ipairs(hint_types) do
track(prefix .. hint_type)
track(prefix .. decl_class .. "/" .. hint_type)
end
end
dotrack("")
if args.short_m or args.short_f or args.short_n or args.short_p then
dotrack("short")
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
dotrack("reducible")
dotrack("reducible/" .. short_accent)
end
if rfind(orig_short_accent, "%(1%)") then
dotrack("special-case-1")
dotrack("special-case-1/" .. short_accent)
end
if rfind(orig_short_accent, "%(2%)") then
dotrack("special-case-2")
dotrack("special-case-2/" .. short_accent)
end
end
if short_accent then
dotrack("short-accent/" .. short_accent)
if datedrare == "dated" then
dotrack("short-accent-dated")
dotrack("short-accent-dated/" .. short_accent)
elseif datedrare == "rare" then
dotrack("short-accent-rare")
dotrack("short-accent-rare/" .. short_accent)
end
elseif datedrare == "none" then
dotrack("short-accent/none")
else
dotrack("short-accent/unknown")
end
if short_stem then
dotrack("explicit-short-stem")
dotrack("explicit-short-stem/" .. short_accent)
end
for _, case in ipairs(all_cases) do
if args[case] then
track("irreg/" .. case)
-- questionable use: dotrack("irreg/" .. case)
end
end
end
-- Insert the category CAT (a string) into list CATEGORIES. String will
-- have "Russian " prepended and ~ substituted for the part of speech.
local function insert_category(categories, cat, plpos)
-- table.insert(categories, "Russian " .. rsub(cat, "~", plpos))
end
categorize = function(decl_type, args, orig_short_accent, short_accent,
short_stem)
local plpos = args.real_surname and "surnames" or args.pronoun and "pronouns" or "adjectives"
-- Insert category CAT into the list of categories in ARGS.
local function insert_cat(cat)
-- insert_category(args.categories, cat, plpos)
end
-- FIXME: For compatibility with old {{temp|ru-adj7}}, {{temp|ru-adj8}},
-- {{temp|ru-adj9}}; maybe there's a better way.
if m_table.contains({"ьій", "ьий", "ьей", "short", "stressed-short", "й-short", "mixed",
"proper", "stressed-proper"}, decl_type) then
-- insert_cat("possessive ~")
end
if not args.pronoun then
if m_table.contains({"ьій", "ьий", "ьей"}, decl_type) then
-- insert_cat("long possessive ~")
elseif m_table.contains({"short", "stressed-short", "й-short"}, decl_type) then
-- insert_cat("short possessive ~")
elseif m_table.contains({"mixed"}, decl_type) then
-- insert_cat("mixed possessive ~")
elseif m_table.contains({"proper", "stressed-proper"}, decl_type) then
-- Don't insert a category like [[:Category:Russian proper-name surnames]]. Instead, rely on
-- [[:Category:Russian possessive surnames]] generated above.
if not args.real_surname then
-- insert_cat("proper-name ~")
end
elseif decl_type == "$" then
-- insert_cat("indeclinable ~")
else
local hint_types = com.get_stem_trailing_letter_type(args.stem)
-- insert English version of Zaliznyak stem type
local stem_type =
m_table.contains(hint_types, "velar") and "velar-stem" or
m_table.contains(hint_types, "sibilant") and "sibilant-stem" or
m_table.contains(hint_types, "c") and "ц-stem" or
m_table.contains(hint_types, "i") and "i-stem" or
m_table.contains(hint_types, "vowel") and "vowel-stem" or
m_table.contains(hint_types, "soft-cons") and "vowel-stem" or
m_table.contains(hint_types, "palatal") and "vowel-stem" or
decl_type == "ий" and "soft-stem" or
"hard-stem"
if stem_type == "soft-stem" or stem_type == "vowel-stem" then
-- insert_cat(stem_type .. " ~")
else
-- insert_cat(stem_type .. " " .. (m_table.contains({"ой", "ьей", "й-short"}, decl_type) and "ending-stressed" or "stem-stressed") .. " ~")
end
end
if m_table.contains({"ой", "ьей", "й-short"}, decl_type) then
-- insert_cat("ending-stressed ~")
end
end
local short_forms_allowed = m_table.contains({"ый", "ой", "ій", "ий"}, decl_type)
if short_forms_allowed then
local override_m = args.short_m
local override_f = args.short_f
local override_n = args.short_n
local override_p = args.short_p
local has_short = short_accent or override_m or override_f or
override_n or override_p
local missing_short = override_m == "-" or
override_f == "-" or override_n == "-" or override_p == "-" or
not short_accent and (not override_m or not override_f or
not override_n or not override_p)
if has_short then
insert_cat("~ with short forms")
if missing_short then
-- insert_cat("~ with missing short forms")
end
end
if short_accent then
-- insert_cat("~ with short accent pattern " .. (short_accent:gsub("''", "ʺ"):gsub("'", "ʹ")))
end
if orig_short_accent then
if rfind(orig_short_accent, "%*") then
-- insert_cat("~ with reducible short stem")
end
if rfind(orig_short_accent, "%(1%)") then
-- insert_cat("~ with Zaliznyak short form special case 1")
end
if rfind(orig_short_accent, "%(2%)") then
-- insert_cat("~ with Zaliznyak short form special case 2")
end
end
if short_stem and short_stem ~= args.stem then
insert_cat("~ with irregular short stem")
end
end
for _, case in ipairs(all_cases) do
if args[case] and args[case] ~= "-" then
local engcase = rsub(case, "^([a-z]*)", {
nom="nominative", gen="genitive", dat="dative",
acc="accusative", ins="instrumental", pre="prepositional",
short="short",
})
engcase = rsub(engcase, "(_[a-z]*)$", {
_m=" masculine singular", _f=" feminine singular",
_n=" neuter singular", _p=" plural",
_mp=" masculine plural"
})
-- insert_cat("~ with irregular " .. engcase)
end
end
if args.nofull then
-- insert_cat("short-form-only ~")
end
end
--------------------------------------------------------------------------
-- Autodetection and stem munging --
--------------------------------------------------------------------------
-- Attempt to detect the type of the lemma based on its ending, separating
-- off the base and the ending; also extract the accent type for short
-- adjectives and optional short stem. DECL is the value passed in, and
-- might already specify the ending. Return five values: STEM, STEMTR, DECL,
-- SHORT_ACCENT (accent class of short adjective, or nil for no short
-- adjectives other than specified through overrides), SHORT_STEM (special
-- stem of short adjective, nil if same as long stem). The return value of
-- SHORT_STEM is taken directly from the argument and will include any
-- manual translit.
detect_stem_and_accent_type = function(lemma, tr, decl, args)
local datedrare = false
-- If it looks like a short decl type, canonicalize. [abc] for types
-- a, b, c'', etc.; [d] for dated-*; [r] for rare-*;
-- [-] for - (no short forms); [*(] for * and (1) and (2) modifiers,
-- which might precede the letter.
if rfind(decl, "^[abcdr*(-]") then
decl = ":" .. decl
end
local splitvals = rsplit(decl, ":")
if #splitvals > 3 then
error("Should be at most three colon-separated parts of a declension spec: " .. decl)
end
local short_accent, short_stem
decl, short_accent, short_stem = splitvals[1], splitvals[2], splitvals[3]
-- Check for dated variant of short accent
local dated_short = short_accent and rmatch(short_accent, "^dated%-(.*)$")
if dated_short then
datedrare = "dated"
short_accent = dated_short
else
-- Check for rare variant of short accent
local rare_short = short_accent and rmatch(short_accent, "^rare%-(.*)$")
if rare_short then
datedrare = "rare"
short_accent = rare_short
end
end
decl = ine(decl)
-- Resolve aliases
if decl then
decl = rsub(decl, "^ъ%-", "")
end
if short_accent == "-" then
short_accent = nil
datedrare = "none"
end
short_accent = ine(short_accent)
short_stem = ine(short_stem)
if short_stem and not short_accent then
error("With explicit short stem " .. short_stem .. ", must specify short accent")
end
local base, ending
-- The while loop appears to function solely as a way of allowing a
-- jump to the end of the loop with a 'break' statement. I don't think
-- the loop is ever run more than once.
while true do
if not decl or decl == "ь" then
base, ending = rmatch(lemma, "^(.*)([ыиіое]́?й)$")
if base then
if ending == "ий" and decl == "ь" then
ending = "ьий"
elseif ending == "ій" and decl == "ь" then
ending = "ьій"
elseif ending == "е́й" or (ending == "ей" and com.is_monosyllabic(lemma)) then
ending = "ье́й"
end
tr = com.strip_tr_ending(tr, ending)
-- -ий/-ій will be converted to -ый after velars and sibilants
-- by the caller
decl = com.make_unstressed(ending)
break
else
-- It appears that short, mixed and proper adjectives are always
-- either of the -ов/ев/ёв or -ин/ын types. The former type is
-- always (or almost always?) short, while the latter can be
-- either; apparently mixed is the more "modern" type of
-- declension, and short is "older". However, both -ов/ев/ёв or
-- -ин/ын are of type "proper" (similar to "short") when
-- capitalized.
--
-- NOTE: Following regexp is accented
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]́н)ъ?$")
if base then
decl = "stressed-proper"
break
end
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[еёо]́?в)ъ?$")
if not base then
-- Following regexp is not stressed
base = rmatch(lemma, "^([" .. com.uppercase .. "].*[иы]н)ъ?$")
end
if base then
decl = "proper"
break
end
base = rmatch(lemma, "^(.*[еёо]́?в)ъ?$")
if base then
decl = "short"
break
end
base = rmatch(lemma, "(.*[иы]́н)ъ?$") --accented
if base then
decl = "stressed-short"
break
end
base = rmatch(lemma, "(.*[иы]н)ъ?$") --unaccented
if base then
decl = "mixed"
break
-- error("With -ин/ын adjectives, must specify 'short' or 'mixed':" .. lemma)
end
error("Cannot determine stem type of adjective: " .. lemma)
end
elseif m_table.contains({"short", "stressed-short", "mixed", "proper",
"stressed-proper"}, decl) then
base = rmatch(lemma, "^(.-)ъ?$")
assert(base)
break
elseif decl == "й" or decl == "й-short" then
base = rmatch(lemma, "^(.-)й$")
assert(base)
tr = com.strip_tr_ending(tr, "й")
decl = "й-short"
break
else
base = lemma
break
end
end
if not datedrare and (args.refl or not (decl == "ый" or decl == "ий" and not rfind(base, "[цс]к$"))) then
datedrare = "none"
end
return base, tr, decl, short_accent, short_stem, datedrare
end
-- Add a possible suffix to the bare stem, according to the declension and
-- value of OLD. This may be -ь, -ъ, -й or nothing. We need to do this here
-- because we don't actually attach such a suffix in attach_unstressed() due
-- to situations where we don't want the suffix added, e.g. бескра́йний with
-- dereduced nom sg бескра́ен without expected -ь.
local function add_bare_suffix(bare, baretr, old, decl, dereduced)
if decl == "й-short" then
return bare .. "й", baretr and baretr .. "j" or nil
elseif old and decl ~= "ій" and decl ~= "$" then
return bare .. "ъ", baretr
elseif decl == "ий" or decl == "ій" then
-- This next special case is mentioned in Zaliznyak's 1980 grammatical
-- dictionary for adjectives (footnote, p. 60).
if dereduced and rfind(bare, "[нН]$") then
-- FIXME: What happens in this case old-style? I assume that
-- -ъ is added, but this is a guess.
return bare .. (old and "ъ" or ""), baretr
elseif rfind(bare, "[" .. com.vowel .. "]́?$") then
-- This happens with adjectives like длинноше́ий, short masculine
-- singular длинноше́й.
return bare .. "й", baretr and baretr .. "j" or nil
else
return bare .. "ь", baretr and baretr .. "ʹ" or nil
end
else
return bare, baretr
end
end
-- Construct and set bare and short form in args, and canonicalize
-- short accent spec, handling cases *, (1) and (2). Return canonicalized
-- short accent and the short declension, which is usually the same as
-- the corresponding long one.
construct_bare_and_short_stem = function(args, short_accent, short_stem,
short_stemtr, accented_stem, accented_stemtr, old, decl)
-- Check if short forms allowed; if not, no short-form params can be given.
-- Construct bare version of stem; used for cases where the ending
-- is non-syllabic (i.e. short masculine singular of long adjectives,
-- and masculine singular of short, mixed and proper adjectives). Comes
-- from short masculine or 3rd argument if explicitly given, else from the
-- accented stem, possibly with the dereduction transformation applied
-- (if * occurs in the short accent spec).
local reducible, sc1, sc2
if short_accent then
short_accent, reducible = rsubb(short_accent, "%*", "")
short_accent, sc1 = rsubb(short_accent, "%(1%)", "")
short_accent, sc2 = rsubb(short_accent, "%(2%)", "")
end
if sc1 or sc2 then
-- Reducible isn't compatible with sc1 or sc2, but Zaliznyak's
-- dictionary always seems to notate sc1 and sc2 with reducible *,
-- so ignore it.
reducible = false
end
if sc1 and sc2 then
error("Special cases 1 and 2, i.e. (1) and (2), not compatible")
end
local short_decl = decl
-- Construct short stem. May be explicitly given, else comes from
-- end-accented stem.
if not short_stem then
short_stem, short_stemtr = accented_stem, accented_stemtr
end
-- Try to accent unaccented short stem (happens only when explicitly given),
-- but be conservative -- only if monosyllabic, since otherwise we have
-- no idea where stress should end up; after all, the explicit short stem
-- is for exceptional cases.
if not args.allow_unaccented then
if short_stemtr and com.is_unstressed(short_stem) ~= com.is_unstressed(short_stemtr) then
error("Explicit short stem " .. short_stem .. " and translit " .. short_stemtr .. " must have same accent pattern")
end
if com.is_monosyllabic(short_stem) then
short_stem, short_stemtr = com.make_ending_stressed(short_stem, short_stemtr)
elseif com.needs_accents(short_stem) then
error("Explicit short stem " .. short_stem .. " needs an accent")
end
end
if sc2 then
if not rfind(short_stem, "нн$") then
error("With special case 2, stem needs to end in -нн: " .. short_stem)
end
short_stem = rsub(short_stem, "нн$", "н")
if short_stemtr then
if not rfind(short_stemtr, "nn$") then
error("With special case 2, stem translit needs to end in -nn: " .. short_stemtr)
end
short_stemtr = rsub(short_stemtr, "nn$", "n")
end
end
-- Construct bare form, used for short masculine.
local bare, baretr
if reducible then
bare, baretr = com.dereduce_stem(short_stem, short_stemtr, rfind(short_accent, "^b"))
if not bare then
error("Unable to dereduce stem: " .. short_stem)
end
bare, baretr = add_bare_suffix(bare, baretr, old, decl, true)
else
bare, baretr = short_stem, short_stemtr
if sc1 then
if not rfind(bare, "нн$") then
error("With special case 1, stem needs to end in -нн: " .. bare)
end
bare = rsub(bare, "нн$", "н")
if baretr then
if not rfind(baretr, "nn$") then
error("With special case 1, stem translit needs to end in -nn: " .. baretr)
end
baretr = rsub(baretr, "nn$", "n")
end
end
-- With special case 1 or 2, we don't ever want -ь added, so treat
-- it like a reducible (that may be why these are marked as
-- reducible in Zaliznyak).
bare, baretr = add_bare_suffix(bare, baretr, old, decl, sc1 or sc2)
end
args.short_stem, args.short_stemtr = short_stem, short_stemtr
args.short_ustem, args.short_ustemtr = com.make_unstressed_once(short_stem, short_stemtr)
args.bare, args.baretr = bare, baretr
return short_accent, short_decl
end
--------------------------------------------------------------------------
-- Declensions --
--------------------------------------------------------------------------
declensions["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_p"] = "ые",
["gen_m"] = "ого",
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
declensions["ий"] = {
["nom_m"] = "ий",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_p"] = "ие",
["gen_m"] = "его",
["gen_f"] = "ей",
["gen_p"] = "их",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "им",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "им",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "ем",
["pre_f"] = "ей",
["pre_p"] = "их",
}
declensions["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_p"] = "ы́е",
["gen_m"] = "о́го",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
-- These can be stressed in ничья́ "draw, tie (in sports)".
declensions["ьий"] = {
["nom_m"] = "и́й",
["nom_n"] = "ье́",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ье́го",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ье́му",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ье́",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ье́м",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́х",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́м",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́м",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьём",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́х",
}
declensions["short"] = {
["nom_m"] = "",
["nom_n"] = "о́",
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = "о́",
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́м",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-short"] = mw.clone(declensions["short"])
declensions["stressed-short"]["pre_m"] = "е́"
declensions["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = "е́й",
["gen_p"] = "и́х",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́м",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́м",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ём",
["pre_f"] = "е́й",
["pre_p"] = "и́х",
}
declensions["mixed"] = {
["nom_m"] = "",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"ого", "а2"},
["gen_f"] = "ой",
["gen_p"] = "ых",
["dat_m"] = {"ому", "у2"},
["dat_f"] = "ой",
["dat_p"] = "ым",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ым",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "ом",
["pre_f"] = "ой",
["pre_p"] = "ых",
}
internal_notes_table["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders["mixed"] = {"m"}
internal_notes_table_old["mixed"] = "<sup>2</sup> Obsolete."
internal_notes_genders_old["mixed"] = {"m"}
declensions["proper"] = {
["nom_m"] = "",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́х",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́м",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́м",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "е́",
["pre_f"] = "о́й",
["pre_p"] = "ы́х",
}
declensions["stressed-proper"] = declensions["proper"]
for _, decl in ipairs({"proper", "stressed-proper"}) do
internal_notes_table[decl] = "<sup>1</sup> Rare."
internal_notes_table_old[decl] = "<sup>1</sup> Rare."
internal_notes_genders[decl] = {"f"}
internal_notes_genders_old[decl] = {"f"}
end
declensions["$"] = {
["nom_m"] = "",
["nom_n"] = "",
["nom_f"] = "",
["nom_p"] = "",
["gen_m"] = "",
["gen_f"] = "",
["gen_p"] = "",
["dat_m"] = "",
["dat_f"] = "",
["dat_p"] = "",
["acc_f"] = "",
-- don't do this; instead we default it to nom_n
-- ["acc_n"] = "",
["ins_m"] = "",
["ins_f"] = "",
["ins_p"] = "",
["pre_m"] = "",
["pre_f"] = "",
["pre_p"] = "",
-- for old-style templates, два, оба, compounds of два
["nom_mp"] = "",
["nom_fp"] = "",
["gen_mp"] = "",
["gen_fp"] = "",
["dat_mp"] = "",
["dat_fp"] = "",
-- don't do this; instead we default them to nom_mp, nom_fp
-- ["acc_mp"] = "",
-- ["acc_fp"] = "",
["ins_mp"] = "",
["ins_fp"] = "",
["pre_mp"] = "",
["pre_fp"] = "",
}
declensions_old["ый"] = {
["nom_m"] = "ый",
["nom_n"] = "ое",
["nom_f"] = "ая",
["nom_mp"] = "ые",
["nom_p"] = "ыя",
["gen_m"] = "аго",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "ому",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "ую",
["acc_n"] = "ое",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["ій"] = {
["nom_m"] = "ій",
["nom_n"] = "ее",
["nom_f"] = "яя",
["nom_mp"] = "іе",
["nom_p"] = "ія",
["gen_m"] = "яго",
["gen_f"] = "ей",
["gen_p"] = "ихъ",
["dat_m"] = "ему",
["dat_f"] = "ей",
["dat_p"] = "имъ",
["acc_f"] = "юю",
["acc_n"] = "ее",
["ins_m"] = "имъ",
["ins_f"] = {"ей", "ею"},
["ins_p"] = "ими",
["pre_m"] = "емъ",
["pre_f"] = "ей",
["pre_p"] = "ихъ",
}
declensions_old["ой"] = {
["nom_m"] = "о́й",
["nom_n"] = "о́е",
["nom_f"] = "а́я",
["nom_mp"] = "ы́е",
["nom_p"] = "ы́я",
["gen_m"] = {"а́го", "о́го"},
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "о́му",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́ю",
["acc_n"] = "о́е",
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю"},
["ins_p"] = "ы́ми",
["pre_m"] = "о́мъ",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["ьій"] = {
["nom_m"] = "ій",
["nom_n"] = "ье",
["nom_f"] = "ья",
["nom_p"] = "ьи",
["gen_m"] = "ьяго",
["gen_f"] = "ьей",
["gen_p"] = "ьихъ",
["dat_m"] = "ьему",
["dat_f"] = "ьей",
["dat_p"] = "ьимъ",
["acc_f"] = "ью",
["acc_n"] = "ье",
["ins_m"] = "ьимъ",
["ins_f"] = {"ьей", "ьею"},
["ins_p"] = "ьими",
["pre_m"] = "ьемъ",
["pre_f"] = "ьей",
["pre_p"] = "ьихъ",
}
declensions_old["ьей"] = {
["nom_m"] = "е́й",
["nom_n"] = "ьё",
["nom_f"] = "ья́",
["nom_p"] = "ьи́",
["gen_m"] = "ьего́",
["gen_f"] = "ье́й",
["gen_p"] = "ьи́хъ",
["dat_m"] = "ьему́",
["dat_f"] = "ье́й",
["dat_p"] = "ьи́мъ",
["acc_f"] = "ью́",
["acc_n"] = "ьё",
["ins_m"] = "ьи́мъ",
["ins_f"] = {"ье́й", "ье́ю"},
["ins_p"] = "ьи́ми",
["pre_m"] = "ьёмъ",
["pre_f"] = "ье́й",
["pre_p"] = "ьи́хъ",
}
declensions_old["short"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = "а",
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = "у",
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["stressed-short"] = mw.clone(declensions_old["short"])
declensions_old["stressed-short"]["pre_m"] = "ѣ́"
declensions_old["й-short"] = {
["nom_m"] = "й",
["nom_n"] = "ё",
["nom_f"] = "я́",
["nom_p"] = "и́",
["gen_m"] = "его́",
["gen_f"] = {"е́й", "ея́"},
["gen_p"] = "и́хъ",
["dat_m"] = "ему́",
["dat_f"] = "е́й",
["dat_p"] = "и́мъ",
["acc_f"] = "ю́",
["acc_n"] = "ё",
["ins_m"] = "и́мъ",
["ins_f"] = {"е́й", "е́ю"},
["ins_p"] = "и́ми",
["pre_m"] = "ёмъ",
["pre_f"] = "е́й",
["pre_p"] = "и́хъ",
}
declensions_old["mixed"] = {
["nom_m"] = "ъ",
["nom_n"] = "о",
["nom_f"] = "а",
["nom_p"] = "ы",
["gen_m"] = {"аго", "а1"},
["gen_f"] = "ой",
["gen_p"] = "ыхъ",
["dat_m"] = {"ому", "у1"},
["dat_f"] = "ой",
["dat_p"] = "ымъ",
["acc_f"] = "у",
["acc_n"] = "о",
["ins_m"] = "ымъ",
["ins_f"] = {"ой", "ою"},
["ins_p"] = "ыми",
["pre_m"] = "омъ",
["pre_f"] = "ой",
["pre_p"] = "ыхъ",
}
declensions_old["proper"] = {
["nom_m"] = "ъ",
["nom_n"] = nil,
["nom_f"] = "а́",
["nom_p"] = "ы́",
["gen_m"] = "а́",
["gen_f"] = "о́й",
["gen_p"] = "ы́хъ",
["dat_m"] = "у́",
["dat_f"] = "о́й",
["dat_p"] = "ы́мъ",
["acc_f"] = "у́",
["acc_n"] = nil,
["ins_m"] = "ы́мъ",
["ins_f"] = {"о́й", "о́ю1"},
["ins_p"] = "ы́ми",
["pre_m"] = "ѣ́",
["pre_f"] = "о́й",
["pre_p"] = "ы́хъ",
}
declensions_old["stressed-proper"] = declensions_old["proper"]
declensions_old["$"] = declensions["$"]
local function frob_genitive_masc(decl)
-- signal to combine_stem_and_suffix() to use the special tr_adj()
-- function so that -го gets transliterated to -vo
if type(decl["gen_m"]) == "table" then
local entries = {}
for _, entry in ipairs(decl["gen_m"]) do
table.insert(entries, rsub(entry, "го$", "го<adj>"))
end
decl["gen_m"] = entries
else
decl["gen_m"] = rsub(decl["gen_m"], "го$", "го<adj>")
end
end
-- Frob declensions, adding <adj> to gen_m forms ending in -го. This is
-- a signal to add manual translit early on that renders -го as -vo.
for _, decl in pairs(declensions_old) do
frob_genitive_masc(decl)
end
for _, decl in pairs(declensions) do
frob_genitive_masc(decl)
end
--------------------------------------------------------------------------
-- Declension functions --
--------------------------------------------------------------------------
local function attach_unstressed(args, suf, short)
local stem, stemtr
if short then
stem, stemtr = args.short_stem, args.short_stemtr
else
stem, stemtr = args.stem, args.stemtr
end
if suf == nil then
return nil
elseif nom.nonsyllabic_suffixes[suf] then
if not args.bare then
return nil
elseif rfind(args.bare, "[йьъ]$") then
return {args.bare, args.baretr}
elseif suf == "ъ" then
return com.concat_russian_tr(args.bare, args.baretr, suf, nil, "dopair")
else
return {args.bare, args.baretr}
end
end
suf = com.make_unstressed(suf)
local rules = nom.unstressed_rules[ulower(usub(stem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(stem, stemtr, suf, rules, args.old))
end
local function attach_stressed(args, suf, short)
local ustem, ustemtr
if short then
ustem, ustemtr = args.short_ustem, args.short_ustemtr
else
ustem, ustemtr = args.ustem, args.ustemtr
end
if suf == nil then
return nil
elseif not rfind(suf, "[ё́]") then -- if suf has no "ё" or accent marks
return attach_unstressed(args, suf, short)
end
local rules = nom.stressed_rules[ulower(usub(ustem, -1))]
-- The parens around the return value drop all but the first return value
return (nom.combine_stem_and_suffix(ustem, ustemtr, suf, rules, args.old))
end
local function attach_both(args, suf, short)
local results = {}
-- Examples with stems with ё on Zaliznyak p. 61 list the
-- ending-stressed forms first, so go with that.
-- NOTE: This assumes we get one value returned, not a list of such values.
table.insert(results, attach_stressed(args, suf, short))
table.insert(results, attach_unstressed(args, suf, short))
return results
end
local function attach_with(args, suf, fun, short)
if type(suf) == "table" then
local all_combineds = {}
for _, x in ipairs(suf) do
local combineds = attach_with(args, x, fun, short)
for _, combined in ipairs(combineds) do
table.insert(all_combineds, combined)
end
end
return all_combineds
else
local funval = fun(args, suf, short)
if funval then
local tbl = {}
assert(type(funval) == "table")
if type(funval[1]) ~= "table" then
funval = {funval}
end
for _, x in ipairs(funval) do
table.insert(tbl,
com.concat_paired_russian_tr(x, args.real_suffix))
end
return tbl
else
return {}
end
end
end
local function gen_form(args, decl, case, fun)
if not args.forms[case] then
args.forms[case] = {}
end
insert_forms_into_existing_forms(args.forms[case],
attach_with(args, decl[case], fun, false))
end
decline = function(args, decl, stressed)
local attacher = stressed and attach_stressed or attach_unstressed
for _, case in ipairs(long_cases) do
gen_form(args, decl, case, attacher)
end
end
canonicalize_override = function(args, case)
local val = args[case]
if not val then
return nil
end
val = rsplit(val, "%s*,%s*")
-- auto-accent/check for necessary accents
local newvals = {}
for _, v in ipairs(val) do
local ru, tr = com.split_russian_tr(v)
if not args.allow_unaccented then
if tr and com.is_unstressed(ru) ~= com.is_unstressed(tr) then
error("Override " .. ru .. " and translit " .. tr .. " must have same accent pattern")
end
-- it's safe to accent monosyllabic stems
if com.is_monosyllabic(ru) then
ru, tr = com.make_ending_stressed(ru, tr)
elseif com.needs_accents(ru) then
error("Override " .. ru .. " for case " .. case .. " requires an accent")
end
end
table.insert(newvals, {ru, tr})
end
val = newvals
return val
end
handle_forms_and_overrides = function(args, short_forms_allowed)
local f = args.forms
local function append_note_all(case, value)
value = com.split_russian_tr(value, "dopair")
if f[case] then
for i=1,#f[case] do
f[case][i] = com.concat_paired_russian_tr(f[case][i], value)
end
end
end
local function append_note_last(case, value, gt_one)
value = com.split_russian_tr(value, "dopair")
if f[case] then
local lastarg = #f[case]
if lastarg > (gt_one and 1 or 0) then
f[case][lastarg] = com.concat_paired_russian_tr(f[case][lastarg], value)
end
end
end
for _, case in ipairs(long_cases) do
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
args[case] = canonicalize_override(args, case) or f[case]
end
for _, case in ipairs(short_cases) do
if short_forms_allowed then
if args[case .. "_tail"] then
append_note_last(case, args[case .. "_tail"])
end
if args[case .. "_tailall"] then
append_note_all(case, args[case .. "_tailall"])
end
if args.shorttailall then
append_note_all(case, args.shorttailall)
end
if args.shorttail then
append_note_last(case, args.shorttail, ">1")
end
args[case] = canonicalize_override(args, case) or f[case]
else
args[case] = nil
end
end
-- Convert an empty list to nil, so that an mdash is inserted. This happens,
-- for example, with words like голубой where args.bare is set to nil.
for _, case in ipairs(all_cases) do
if args[case] and #args[case] == 0 then
args[case] = nil
end
end
-- default acc_n to nom_n; applies chiefly in the indeclinable declension
-- (used with manual declension tables)
if not args.acc_n then
args.acc_n = args.nom_n
end
-- default inanimate/animate accusative variants as appropriate; this is
-- almost always correct, but not with e.g. два́дцать оди́н, where the
-- masculine animate accusative два́дцать одного́ differs from both the
-- masculine nominative два́дцать оди́н and the masculine genitive
-- двадцати́ одного́.
if not args.acc_m_an then
args.acc_m_an = args.gen_m
end
if not args.acc_m_in then
args.acc_m_in = args.nom_m
end
-- Compounds of два do not have animacy; everything else does.
-- Only copy either the with-animacy or without-animacy variants to avoid
-- having both forms in {{ru-generate-adj-forms}}.
if args.special ~= "cdva" then
if not args.acc_p_an then
args.acc_p_an = args.gen_p
end
if not args.acc_p_in then
args.acc_p_in = args.nom_p
end
if not args.acc_mp_an then
args.acc_mp_an = args.gen_mp
end
if not args.acc_mp_in then
args.acc_mp_in = args.nom_mp
end
if not args.acc_fp_an then
args.acc_fp_an = args.gen_fp
end
if not args.acc_fp_in then
args.acc_fp_in = args.nom_fp
end
else
if not args.acc_mp then
args.acc_mp = args.nom_mp
end
if not args.acc_fp then
args.acc_fp = args.nom_fp
end
end
end
--------------------------------------------------------------------------
-- Short adjective declension --
--------------------------------------------------------------------------
short_declensions["ый"] = { m="", f="а́", n="о́", p="ы́" }
short_declensions["ой"] = short_declensions["ый"]
short_declensions["ий"] = { m="ь", f="я́", n="е́", p="и́" }
short_declensions_old["ый"] = { m="ъ", f="а́", n="о́", p="ы́" }
short_declensions_old["ой"] = short_declensions_old["ый"]
short_declensions_old["ій"] = short_declensions["ий"]
-- Short adjective stress patterns:
-- "-" = stem-stressed
-- "+" = ending-stressed (drawn onto the last syllable of stem in masculine)
-- "-+" = both possibilities
short_stress_patterns["a"] = { m="-", f="-", n="-", p="-" }
short_stress_patterns["a'"] = { m="-", f="-+", n="-", p="-" }
short_stress_patterns["b"] = { m="+", f="+", n="+", p="+" }
short_stress_patterns["b'"] = { m="+", f="+", n="+", p="-+" }
short_stress_patterns["c"] = { m="-", f="+", n="-", p="-" }
short_stress_patterns["c'"] = { m="-", f="+", n="-", p="-+" }
short_stress_patterns["c''"] = { m="-", f="+", n="-+", p="-+" }
local function gen_short_form(args, decl, case, fun, datedrare)
if not args.forms["short_" .. case] then
args.forms["short_" .. case] = {}
end
local inserted = insert_forms_into_existing_forms(
args.forms["short_" .. case], attach_with(args, decl[case], fun, true),
(datedrare == "dated" and datedrare == "rare") and "*" or nil)
if datedrare == "dated" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Dated.")
elseif datedrare == "rare" and inserted then
m_table.insertIfNot(args.internal_notes, "<sup>*</sup> Rare.")
end
end
local attachers = {
["+"] = attach_stressed,
["-"] = attach_unstressed,
["-+"] = attach_both,
}
decline_short = function(args, decl, stress_pattern, dated)
if stress_pattern then
for _, case in ipairs({"m", "f", "n", "p"}) do
gen_short_form(args, decl, case, attachers[stress_pattern[case]],
dated)
end
end
end
--------------------------------------------------------------------------
-- Create the table --
--------------------------------------------------------------------------
local title_temp = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local old_title_temp = [=[မလဟုတ်စှ်ေကၠာပြုပြေၚ်ပြံၚ်လှာဲဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b> ({short_class_title})]=]
local title_temp_no_short_msg = [=[မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local old_title_temp_no_short_msg = [=[မလဟုတ်စှ်ေကၠာပြုပြေၚ်ပြံၚ်လှာဲဆေၚ်စပ်ကဵု <b lang="ru" class="Cyrl">{lemma}</b>]=]
local template = nil
local full_clause = nil
local template_no_neuter = nil
local full_clause_no_neuter = nil
local surname_full_clause = nil
local template_mp = nil
local full_clause_mp = nil
local template_mp_no_neuter = nil
local full_clause_mp_no_neuter = nil
local surname_full_clause_mp = nil
local template_dva = nil
local full_clause_dva = nil
local full_clause_compound_dva = nil
local template_oba = nil
local full_clause_oba = nil
local short_clause_separator = nil
local short_clause = nil
local short_clause_no_neuter_separator = nil
local short_clause_no_neuter = nil
local short_clause_mp_separator = nil
local short_clause_mp = nil
local short_clause_mp_no_neuter_separator = nil
local short_clause_mp_no_neuter = nil
local internal_notes_template = nil
local notes_template = nil
local function get_accel_forms(old, special, has_nom_mp)
return {
-- used with all variants
nom_m = "nom|m|s",
nom_f = "nom|f|s",
nom_n = "nom|n|s",
-- not used with special; applies to all genders normally but only
-- feminine and neuter with old=1
nom_p = old and has_nom_mp and "nom|f//n|p" or "nom|p",
-- only used with old=1 or special; applies to the masculine and neuter if
-- special, but only masculine if old=1
nom_mp = special and "nom|m//n|p" or "nom|m|p",
-- only used with special
nom_fp = "nom|f|p",
-- the remaining singulars and non-gendered plurals used with all variants
-- except special == "oba"
gen_m = "gen|m//n|s",
gen_f = "gen|f|s",
gen_p = "gen|p",
dat_m = "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",
-- the following two not used with special in ("dva", "oba"); applies to
-- all genders normally but only feminine and neuter with old=1
acc_p_an = old and has_nom_mp and "an|acc|f//n|p" or "an|acc|p",
acc_p_in = old and has_nom_mp and "in|acc|f//n|p" or "in|acc|p",
-- the following two only used with old=1 or special in ("dva|oba");
-- applies to the masculine and neuter if special, but only masculine if
-- old=1
acc_mp_an = special and "an|acc|m//n|p" or "an|acc|m|p",
acc_mp_in = special and "in|acc|m//n|p" or "in|acc|m|p",
-- the following two only used with special in ("dva", "oba")
acc_fp_an = "an|acc|f|p",
acc_fp_in = "in|acc|f|p",
-- the next 6 are used with all variants except special == "oba"
ins_m = "ins|m//n|s",
ins_f = "ins|f|s",
ins_p = "ins|p",
pre_m = "pre|m//n|s",
pre_f = "pre|f|s",
pre_p = "pre|p",
-- the following two gendered plurals are only used with special == "cdva"
acc_mp = "acc|m//n|p",
acc_fp = "acc|f|p",
-- the remaining gendered plurals are only used with special == "oba"
gen_mp = "gen|m//n|p",
gen_fp = "gen|f|p",
dat_mp = "dat|m//n|p",
dat_fp = "dat|f|p",
ins_mp = "ins|m//n|p",
ins_fp = "ins|f|p",
pre_mp = "pre|m//n|p",
pre_fp = "pre|f|p",
-- short forms
short_m = "short|m|s",
short_f = "short|f|s",
short_n = "short|n|s",
short_p = "short|p",
}
end
-- Make the table
make_table = function(args)
local lemma_forms = args.special and args.nom_mp or
args.nofull and args.short_m or args.nom_m
args.lemma = m_links.remove_links(nom.show_form(lemma_forms, true, nil, nil))
args.title = args.title or strutils.format(
(args.special or args.manual) and args.old and old_title_temp_no_short_msg or
(args.special or args.manual) and title_temp_no_short_msg or
args.old and old_title_temp or
title_temp,
args)
local has_nom_mp = args.nom_mp and not (#args.nom_mp == 1 and args.nom_mp[1][1] == "-")
local accel_forms = get_accel_forms(args.old, args.special, has_nom_mp)
for _, case in ipairs(all_cases) do
if args[case] then
local accel_form = accel_forms[case]
if not accel_form then
error("Internal error: Unrecognized case " .. case .. " when looking up accelerator form")
end
if args.noneuter or args.real_surname then
accel_form = rsub(accel_form, "//n", "")
end
if args.real_surname then
accel_form = rsub(accel_form, "an|", "")
end
args[case] = nom.show_form(args[case], false, accel_form, lemma_forms)
else
args[case] = nil
end
end
local temp, fullc
if args.special == "oba" then
temp = template_oba
fullc = full_clause_oba
elseif args.special == "dva" then
temp = template_dva
fullc = full_clause_dva
elseif args.special == "cdva" then
temp = template_dva -- no template_cdva
fullc = full_clause_compound_dva
elseif args.real_surname and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = surname_full_clause_mp
elseif args.real_surname then
temp = template_no_neuter
fullc = surname_full_clause
elseif args.noneuter and args.old and has_nom_mp then
temp = template_mp_no_neuter
fullc = full_clause_mp_no_neuter
elseif args.noneuter then
temp = template_no_neuter
fullc = full_clause_no_neuter
elseif args.old and has_nom_mp then
temp = template_mp
fullc = full_clause_mp
else
temp = template
fullc = full_clause
end
if args.old then
if has_nom_mp then
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_mp_no_neuter_separator or short_clause_mp_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_mp_no_neuter or short_clause_mp, args)
else
args.short_clause = ""
end
else
args.short_clause = ""
end
else
if args.short_m or args.short_n or args.short_f or args.short_p then
args.short_m = args.short_m or "—"
args.short_n = args.short_n or "—"
args.short_f = args.short_f or "—"
args.short_p = args.short_p or "—"
args.shortsep = not args.nofull and (
args.noneuter and short_clause_no_neuter_separator or short_clause_separator
) or ""
args.short_clause = strutils.format(args.noneuter and short_clause_no_neuter or short_clause, args)
else
args.short_clause = ""
end
end
if not args.nofull then
args.full_clause = strutils.format(fullc, args)
else
args.full_clause = ""
end
args.internal_notes = table.concat(args.internal_notes, "<br />")
args.internal_notes_clause = #args.internal_notes > 0 and strutils.format(internal_notes_template, args) or ""
args.notes_clause = args.notes and strutils.format(notes_template, args) or ""
return strutils.format(temp, args)
end
-- Used for new-style templates
short_clause_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for new-style templates
short_clause = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for new-style templates
short_clause_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=5 |
|-
]===]
-- Used for new-style templates
short_clause_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=7 |
|-
]===]
-- Used for old-style templates
short_clause_mp = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=3 | {short_n}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for old-style templates
short_clause_mp_no_neuter_separator = [===[
! style="height:0.2em;background:var(--wikt-palette-lightblue)" colspan=6 |
|-
]===]
-- Used for old-style templates
short_clause_mp_no_neuter = [===[
{shortsep}! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗီုပြၚ်ဓမၠေံ
| data-accel-col=1 | {short_m}
| data-accel-col=2 | {short_f}
| data-accel-col=4 colspan=2 | {short_p}]===]
-- Used for both new-style and old-style templates
notes_template = [===[
<div style="width:100%;text-align:left">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{notes}
</div></div>
]===]
-- Used for both new-style and old-style templates
internal_notes_template = rsub(notes_template, "notes", "internal_notes")
local function template_prelude(min_width)
min_width = min_width or "70"
return rsub([===[
<div>
<div class="NavFrame">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue)">{title}</div>
<div class="NavContent">
{\op}| style="background:var(--wikt-palette-paleblue);text-align:center" class="inflection-table"
|-
]===], "MINWIDTH", min_width)
end
local function template_postlude()
return [===[{full_clause}|-{short_clause}
|{\cl}{internal_notes_clause}{notes_clause}</div></div></div>]===]
end
-- Used for both new-style and old-style templates
template = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
template_no_neuter = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates
full_clause_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for both new-style and old-style templates
surname_full_clause = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_p}
]===]
-- Used for old-style templates
template_mp = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်/ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for old-style templates
template_mp_no_neuter = template_prelude("60") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for old-style templates
full_clause_mp_no_neuter = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_p_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for some old-style templates
surname_full_clause_mp = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=1 | {acc_m_an}
| data-accel-col=2 | {acc_f}
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for два and compounds
template_dva = template_prelude("55") .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်/နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of два (only for два itself,
-- which has an animacy distinction; not for compounds)
full_clause_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=4 colspan=2 | {acc_p_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for both new-style and old-style templates of compounds of два
full_clause_compound_dva = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=4 colspan=2 | {gen_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=4 colspan=2 | {dat_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ကမ္မကာရက
| data-accel-col=4 | {acc_mp}
| data-accel-col=5 | {acc_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=4 colspan=2 | {ins_p}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=4 colspan=2 | {pre_p}
]===]
-- Used for оба
template_oba = template_prelude() .. [===[
! style="width:20%;background:var(--wikt-palette-lightblue)" colspan=2 |
! style="background:var(--wikt-palette-lightblue)" | ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | နပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ဣတ္တိလိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်နပုလ္လိၚ်/ပုလ္လိၚ်
! style="background:var(--wikt-palette-lightblue)" | ကိုန်ဗဟုဝစ်ဣတ္တိလိၚ်
]===] .. template_postlude()
-- Used for both new-style and old-style templates of оба
full_clause_oba = [===[
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | မဒုၚ်ယၟု
| data-accel-col=1 | {nom_m}
| data-accel-col=3 | {nom_n}
| data-accel-col=2 | {nom_f}
| data-accel-col=4 | {nom_mp}
| data-accel-col=5 | {nom_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဗဳဇဂကူ
| data-accel-col=1 colspan=2 | {gen_m}
| data-accel-col=2 | {gen_f}
| data-accel-col=4 | {gen_mp}
| data-accel-col=5 | {gen_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ပြကမ္မကာရက
| data-accel-col=1 colspan=2 | {dat_m}
| data-accel-col=2 | {dat_f}
| data-accel-col=4 | {dat_mp}
| data-accel-col=5 | {dat_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" rowspan=2 | ကမ္မကာရက
! style="background:var(--wikt-palette-lighterblue)" | ဆေၚ်စပ်ကဵုသတ်
| data-accel-col=1 | {acc_m_an}
| data-accel-col=3 rowspan=2 | {acc_n}
| data-accel-col=2 rowspan=2 | {acc_f}
| data-accel-col=4 | {acc_mp_an}
| data-accel-col=5 | {acc_fp_an}
|-
! style="background:var(--wikt-palette-lighterblue)" | မသက္ကုဟၟဲကဵုလမျီု
| data-accel-col=1 | {acc_m_in}
| data-accel-col=4 | {acc_mp_in}
| data-accel-col=5 | {acc_fp_in}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 colspan=2 | {ins_m}
| data-accel-col=2 | {ins_f}
| data-accel-col=4 | {ins_mp}
| data-accel-col=5 | {ins_fp}
|-
! style="background:var(--wikt-palette-lighterblue)" colspan=2 | ဆေၚ်စပ်ကဵုဝိဘတ်
| data-accel-col=1 colspan=2 | {pre_m}
| data-accel-col=2 | {pre_f}
| data-accel-col=4 | {pre_mp}
| data-accel-col=5 | {pre_fp}
]===]
return export
cmbf7nw6d8jzytaaw5v60barvldexag
မဝ်ဂျူ:uk-be-headword
828
25177
399817
272771
2026-07-21T07:20:12Z
咽頭べさ
33
399817
Scribunto
text/plain
local export = {}
local force_cat = false -- for testing; if true, categories appear in non-mainspace pages
local lang, langcode, langname
local com
local m_links = require("Module:links")
local require_when_needed = require("Module:require when needed")
local m_table = require("Module:table")
local en_utilities_module = "Module:en-utilities"
local headword_utilities_module = "Module:headword utilities"
local inflection_utilities_module = "Module:inflection utilities"
local string_utilities_module = "Module:string utilities"
local m_en_utilities = require_when_needed(en_utilities_module)
local m_headword_utilities = require_when_needed(headword_utilities_module)
local m_inflection_utilities = require_when_needed(inflection_utilities_module)
local m_string_utilities = require_when_needed(string_utilities_module)
local glossary_link = require_when_needed(headword_utilities_module, "glossary_link")
local boolean_param = {type = "boolean"}
local list_param = {list = true, disallow_holes = true}
local boolean_param = {type = "boolean"}
local list_param = {list = true, disallow_holes = true}
local list_comp = {list = "comp", disallow_holes = true}
local list_sup = {list = "sup", disallow_holes = true}
local concat = table.concat
local insert = table.insert
local pos_functions = {}
local function track(page)
require("Module:debug").track(langcode .. "-headword/" .. page)
return true
end
local function check_if_accent_needed(val, data)
val = m_links.remove_links(val)
if com.needs_accents(val) then
if langcode == "uk" and not data.unknown_stress then
error("Stress must be supplied using an acute accent: '" .. val .. "' (use unknown_stress=1 if stress is truly unknown)")
end
local pos = require(en_utilities_module).singularize(data.pos_category)
insert(data.categories, "Requests for accents in " .. langname .. " " .. pos .. " entries")
end
if com.is_multi_stressed(val) then
error("Multi-stressed form '" .. val .. "' not allowed")
end
end
-- Parse an inflection. The raw arguments come from `args[field]`, which is parsed for inline modifiers. Multiple
-- comma-separated values are allowed.
local function parse_inflection(data, args, field, is_head)
local argfield = field
if type(argfield) == "table" then
argfield = argfield[1]
end
return m_headword_utilities.parse_term_list_with_modifiers {
forms = args[argfield],
paramname = field,
splitchar = ",",
is_head = is_head,
include_mods = {"tr"},
frob = function(term)
check_if_accent_needed(term, data)
return term
end,
}
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw arguments come
-- from `args[field]`, which is parsed for inline modifiers. Multiple comma-separated values are allowed. `label` is the
-- label that the inflections are given; sections enclosed in <<...>> are linked to the glossary. `accel_form` is the
-- accelerator form, or nil.
local function parse_and_insert_inflection(data, args, field, label, accel_form)
local terms = parse_inflection(data, args, field)
m_headword_utilities.insert_inflection {
headdata = data,
terms = terms,
label = label,
accel = accel_form and {form = accel_form} or nil,
}
end
-- 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
local PAGENAME = mw.loadData("Module:headword/data").pagename
local required = {required = true}
local iparams = {
[1] = required,
["lang"] = required,
}
local iargs = require("Module:parameters").process(frame.args, iparams)
local poscat = iargs[1]
langcode = iargs.lang
if langcode ~= "uk" and langcode ~= "be" then
error("This module currently only works for lang=uk and lang=be")
end
lang = require("Module:languages").getByCode(langcode)
langname = langcode == "uk" and "ယူကရိန်" or "ဗါလာရုဇ်"
com = langcode == "uk" and require("Module:uk-common") or require("Module:be-common")
local params = {
[1] = {list = "head", disallow_holes = true},
["unknown_stress"] = boolean_param,
["pagename"] = true,
["id"] = true,
}
if pos_functions[poscat] then
for key, val in pairs(pos_functions[poscat].params) do
params[key] = val
end
end
local parargs = frame:getParent().args
local args = require("Module:parameters").process(parargs, params)
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local data = {
lang = lang,
no_redundant_head_cat = true,
pos_category = poscat,
categories = {},
genders = {},
inflections = {},
id = args.id,
pagename = pagename,
unknown_stress = args.unknown_stress,
frame = frame,
}
if not pos_functions[poscat] or not pos_functions[poscat].no_parse_heads or
not pos_functions[poscat].no_parse_heads(args) then
data.heads = parse_inflection(data, args, {1, "head"}, "is_head")
if not data.heads[1] then
data.heads = {{term = pagename}}
end
end
if args.unknown_stress then
insert(data.inflections, {label = "unknown stress"})
end
if pos_functions[poscat] then
pos_functions[poscat].func(args, data)
end
return require("Module:headword").full_headword(data) .. (data.extra_text or "")
end
local function make_gloss_text(text)
return '<span class="mention-gloss-paren">(</span>' ..
'<span class="mention-gloss">' .. text ..
'</span><span class="mention-gloss-paren">)</span>'
end
local function noun_no_parse_heads(args)
return not args[3][1] and not args[4][1] and not args[5][1] and not args[1][2] and
args[1][1] and args[1][1]:find("<")
end
local function get_noun_pos(is_proper)
return {
params = {
[2] = {list = "g", type = "genders", disallow_holes = true, flatten = true},
[3] = {list = "gen", disallow_holes = true},
[4] = {list = "pl", disallow_holes = true},
[5] = {list = "genpl", disallow_holes = true},
["lemma"] = list_param,
["m"] = list_param,
["f"] = list_param,
["adj"] = list_param,
["poss"] = list_param,
["dim"] = list_param,
["aug"] = list_param,
["pej"] = list_param,
["dem"] = list_param,
["fdem"] = list_param,
["unknown_gender"] = boolean_param,
["unknown_animacy"] = boolean_param,
},
-- set this to avoid problems with cases like {{uk-noun|((ґандж<>,ґандж<F>))}},
-- which will otherwise throw an error
no_parse_heads = noun_no_parse_heads,
func = function(args, data)
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw
-- arguments come from `args[field]`, which is parsed for inline modifiers. `label` is the label that the
-- inflections are given; <<..>> in the label is linked to the glossary).
local function handle_infl(field, label)
parse_and_insert_inflection(data, args, field, label)
end
local genitives, plurals, genitive_plurals, usuallysg
if noun_no_parse_heads(args) then
args[1] = args[1][1]
local alternant_spec = require("မဝ်ဂျူ:" .. langcode .. "-noun").do_generate_forms(args, nil, true)
local footnote_obj
local function convert_formobjs_to_termobjs(formobjs)
local termobjs = {}
if formobjs then
for _, formobj in ipairs(formobjs) do
local termobj = {
term = langcode == "uk" and com.remove_monosyllabic_stress(formobj.form) or
com.remove_monosyllabic_accents(formobj.form)
}
if formobj.footnotes then
-- FIXME, we (or rather, [[Module:inflection utilities]]) should recognize labels like
-- "rare" and "archaic" and convert them automatically to labels.
local quals, refs =
m_inflection_utilities.convert_footnotes_to_qualifiers_and_references(
formobj.footnotes)
termobj.q = quals
termobj.refs = refs
end
insert(termobjs, termobj)
end
end
if not termobjs[1] then
termobjs = {{term = "-"}}
end
return termobjs
end
if alternant_spec.number == "pl" then
data.heads = args.lemma[1] and parse_inflection(data, args, "lemma", "is_head") or
convert_formobjs_to_termobjs(alternant_spec.forms.nom_p_linked)
genitives = convert_formobjs_to_termobjs(alternant_spec.forms.gen_p)
plurals = {{term = "-"}}
genitive_plurals = {{term = "-"}}
else
data.heads = args.lemma[1] and parse_inflection(data, args, "lemma", "is_head") or
convert_formobjs_to_termobjs(alternant_spec.forms.nom_s_linked)
genitives = convert_formobjs_to_termobjs(alternant_spec.forms.gen_s)
if alternant_spec.number == "sg" then
plurals = {{term = "-"}}
genitive_plurals = {{term = "-"}}
else
plurals = convert_formobjs_to_termobjs(alternant_spec.forms.nom_p)
genitive_plurals = convert_formobjs_to_termobjs(alternant_spec.forms.gen_p)
end
end
if args[2][1] then
data.genders = args[2]
else
local gender_specs = {}
for _, g in ipairs(alternant_spec.genders) do
insert(gender_specs, {spec = g})
end
data.genders = gender_specs
end
usuallysg = alternant_spec.usuallysg
else
data.genders = args[2]
if not data.genders[1] then
if mw.title.getCurrentTitle().nsText ~= "ထာမ်ပလိက်" then
error("Gender must be specified")
else
data.genders = {{spec = "m-in"}}
end
end
genitives = parse_inflection(data, args, {3, "gen"})
plurals = parse_inflection(data, args, {4, "pl"})
genitive_plurals = parse_inflection(data, args, {5, "genpl"})
if genitives[1] and genitives[1].term ~= "-" then
-- don't track for indeclinables, which legitimately use the old-style syntax
track(langcode .. "-noun-old-style")
end
end
-- Validate the genders.
local singular_genders = {}
local plural_genders = {}
local allowed_genders = {"m", "f", "n", "mf", "mfbysense"}
if langcode == "be" or args.unknown_gender then
insert(allowed_genders, "?")
end
local allowed_animacies = {"pr", "anml", "in"}
if langcode == "be" or args.unknown_animacy then
insert(allowed_animacies, "?")
end
for _, gender in ipairs(allowed_genders) do
for _, animacy in ipairs(allowed_animacies) do
singular_genders[gender .. "-" .. animacy] = true
plural_genders[gender .. "-" .. animacy .. "-p"] = true
end
end
if langcode == "be" then
singular_genders["?"] = true
plural_genders["?-p"] = true
end
local seen_gender = nil
local seen_animacy = nil
for _, gspec in ipairs(data.genders) do
local g = gspec.spec
if not singular_genders[g] and not plural_genders[g] then
if g:match("%-an%-") or g:match("%-an$") then
error("Invalid animacy 'an'; use 'pr' for people, 'anml' for animals: " .. g)
end
error("Unrecognized gender: " .. g .. " (should be e.g. 'm-pr' for masculine personal, 'f-anml-p' for feminine animal plural, or 'n-in' for neuter inanimate)")
end
end
-- Add the genitive forms.
if genitives[1] and genitives[1].term == "-" then
insert(data.inflections, {label = glossary_link("ကၞိက်ဟွံမာန်")})
insert(data.categories,"နာမ်" .. langname .. "နကဵုပါ်ပါဲထောံဟွံမာန်ဂမၠိုၚ်")
else
genitives.label = "ဗဳဇဂကူ"
genitives.request = true
insert(data.inflections, genitives)
end
-- Add the plural forms.
if genitives[1] and genitives[1].term == "-" then
if plurals[1] or genitive_plurals[1] then
error("Can't specify nominative or genitive plurals of a plural-only term")
end
elseif plural_genders[data.genders[1].spec] then
insert(data.inflections, {label = glossary_link("ပါဲနူကိုန်ဗဟုဝစ်")})
elseif plurals[1] and plurals[1].term == "-" then
insert(data.inflections, {label = glossary_link("မတော်ဟွံမာန်")})
insert(data.categories, "နာမ်" .. langname .. "မတော်ဟွံဂွံဂမၠိုၚ်")
else
if usuallysg then
insert(data.inflections, {label = "ဗွဲတၟေၚ်" .. glossary_link("မတော်ဟွံမာန်")})
insert(data.categories, "နာမ်" .. langname .. "မတော်ဟွံဂွံဂမၠိုၚ်")
end
plurals.label = "မဒုၚ်ယၟုကိုန်ဗဟုဝစ်"
plurals.request = true
insert(data.inflections, plurals)
if genitive_plurals[1] then
-- allow the genitive plural to be unsupplied; formerly there
-- was no genitive plural param
if genitive_plurals[1].term == "-" then
-- handle case where there's no genitive plural (e.g. ага́)
insert(data.inflections, {label = "ဗဳဇဂကူကိုန်ဗဟုဝစ်ဟွံသေၚ်"})
else
genitive_plurals.label = "ဗဳဇဂကူကိုန်ဗဟုဝစ်"
insert(data.inflections, genitive_plurals)
end
end
end
handle_infl("m", "မညဳညတ်သၟတ်တးလိၚ်တြုံ")
handle_infl("f", "မညဳညတ်သၟတ်တးလိၚ်ဗြဴ")
handle_infl("adj", "<<နာမဝိသေသနဒၞာဲမဆက်စပ်>>")
handle_infl("poss", "<<နာမဝိသေသနဓမံက်ထ္ၜးမဒှ်တၠဒြပ်>>")
handle_infl("dim", "<<မလဟုတ်စှ်ေ>>")
handle_infl("aug", "<<ပရေၚ်မဗပေၚ်တိုန်>>")
handle_infl("pej", "<<စမ်ၜတ်ရံၚ်>>")
handle_infl("dem", "<<အပၠေံရုပ်ရာ>>")
handle_infl("fdem", "<<အပၠေံရုပ်ရာ>>ဣတ္တိလိၚ်")
end
}
end
pos_functions["နာမ်မကိတ်ညဳ"] = get_noun_pos(true)
pos_functions["နာမ်"] = get_noun_pos(false)
pos_functions["ကြိယာ"] = {
params = {
[2] = {default = "?"},
["pf"] = list_param,
["impf"] = list_param,
},
func = function(args, data)
-- Aspect
local aspect = args[2]
if aspect == "both" then
aspect = "biasp"
elseif aspect ~= "pf" and aspect ~= "impf" and aspect ~= "biasp" and aspect ~= "?" then
error("Unrecognized aspect: '" .. aspect .. "'")
end
insert(data.genders, aspect)
if args.pf[1] and aspect == "pf" then
error("Can't specify perfective counterparts for a perfective verb")
end
if args.impf[1] and aspect == "impf" then
error("Can't specify imperfective counterparts for an imperfective verb")
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw
-- arguments come from `args[field]`, which is parsed for inline modifiers. `label` is the label that the
-- inflections are given; <<..>> in the label is linked to the glossary).
local function handle_infl(field, label)
parse_and_insert_inflection(data, args, field, label)
end
handle_infl("impf", "ဟွံက္ဍိုပ်ပေၚ်")
handle_infl("pf", "ဗီုပြၚ်မက္ဍိုပ်ပေၚ်")
end
}
pos_functions["နာမဝိသေသန"] = {
params = {
[2] = list_comp,
[3] = list_sup,
["adv"] = list_param,
["absn"] = list_param,
["dim"] = list_param,
["indecl"] = boolean_param,
},
func = function(args, data)
if args.indecl then
insert(data.inflections, {label = "ပြံၚ်လှာဲဟွံမာန်"})
insert(data.categories,"နာမဝိသေသန" .. langname .. "နကဵုပါ်ပါဲထောံဟွံမာန်ဂမၠိုၚ်")
end
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw
-- arguments come from `args[field]`, which is parsed for inline modifiers. `label` is the label that the
-- inflections are given; <<..>> in the label is linked to the glossary).
local function handle_infl(field, label)
parse_and_insert_inflection(data, args, field, label)
end
handle_infl({2, "comp"}, "ပတဝ်ပတုပ်ရံၚ်")
handle_infl({3, "sup"}, "သဒ္ဒာ")
handle_infl("adv", "ကြိယာဝိသေသန")
handle_infl("absn", "နာမ်စိတ္တဇ")
handle_infl("dim", "လဟုတ်စှ်ေ")
end
}
pos_functions["ကြိယာဝိသေသန"] = {
params = {
[2] = list_comp,
[3] = list_sup,
["dim"] = list_param,
},
func = function(args, data)
-- Parse and insert an inflection not requiring additional processing into `data.inflections`. The raw
-- arguments come from `args[field]`, which is parsed for inline modifiers. `label` is the label that the
-- inflections are given; <<..>> in the label is linked to the glossary).
local function handle_infl(field, label)
parse_and_insert_inflection(data, args, field, label)
end
handle_infl({2, "comp"}, "ပတဝ်ပတုပ်ရံၚ်")
handle_infl({3, "sup"}, "သဒ္ဒာ")
handle_infl("dim", "လဟုတ်စှ်ေ")
end
}
return export
8ygfkhh9chh1o6pnzuejryo0do6vryg
ထာမ်ပလိက်:=es=
10
27697
399852
370629
2026-07-21T14:01:52Z
CommonsDelinker
969
Replacing Bandera_de_España.svg with [[File:Flag_of_the_Kingdom_of_Spain.svg]] (by [[:c:User:CommonsDelinker|CommonsDelinker]] because: [[:c:COM:FR|File renamed]]: [[:c:COM:FR#FR4|Criterion 4]]).
399852
wikitext
text/x-wiki
[[File:Flag of the Kingdom of Spain.svg|50px|link=w:en:Spanish language]] သပုၚ်
<noinclude>[[ကဏ္ဍ:ထာမ်ပလိက်ဂမၠိုၚ်|သ]]</noinclude>
odl8zbtntp8qv6tcxburyvnmfg27dwc
မဝ်ဂျူ:uk-noun
828
41402
399805
151136
2026-07-21T04:06:53Z
咽頭べさ
33
399805
Scribunto
text/plain
local export = {}
--[=[
Authorship: Ben Wing <benwing2>
]=]
--[=[
TERMINOLOGY:
-- "slot" = A particular combination of case/number.
Example slot names for nouns are "gen_" (genitive singular) and
"voc_p" (vocative plural). Each slot is filled with zero or more forms.
-- "form" = The declined Ukrainian form representing the value of a given slot.
-- "lemma" = The dictionary form of a given Ukrainian 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("uk")
local m_table = require("Module:table")
local m_links = require("Module:links")
local m_string_utilities = require("Module:string utilities")
local iut = require("Module:inflection utilities")
local put = require("Module:parse utilities")
local m_para = require("Module:parameters")
local com = require("Module:uk-common")
local m_uk_translit = require("Module:uk-translit")
local force_cat = false -- set to true for debugging
local u = require("Module:string/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 usub = mw.ustring.sub
local uupper = mw.ustring.upper
local ulower = mw.ustring.lower
local AC = u(0x0301) -- acute = ́
local CFLEX = u(0x0302) -- circumflex = ̂
local DOTUNDER = u(0x0323) -- dotunder = ̣
local accents = AC .. DOTUNDER
local accents_c = "[" .. accents .. "]"
-- 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
local output_noun_slots = {
nom_s = "nom|s",
gen_s = "gen|s",
dat_s = "dat|s",
acc_s = "acc|s",
ins_s = "ins|s",
loc_s = "loc|s",
voc_s = "voc|s",
nom_p = "nom|p",
gen_p = "gen|p",
dat_p = "dat|p",
acc_p = "acc|p",
ins_p = "ins|p",
loc_p = "loc|p",
voc_p = "voc|p",
}
local output_noun_slots_with_linked = m_table.shallowCopy(output_noun_slots)
output_noun_slots_with_linked["nom_s_linked"] = "nom|s"
output_noun_slots_with_linked["nom_p_linked"] = "nom|p"
local input_params_to_slots_both = {
[1] = "nom_s",
[2] = "nom_p",
[3] = "gen_s",
[4] = "gen_p",
[5] = "dat_s",
[6] = "dat_p",
[7] = "acc_s",
[8] = "acc_p",
[9] = "ins_s",
[10] = "ins_p",
[11] = "loc_s",
[12] = "loc_p",
[13] = "voc_s",
[14] = "voc_p",
}
local input_params_to_slots_sg = {
[1] = "nom_s",
[2] = "gen_s",
[3] = "dat_s",
[4] = "acc_s",
[5] = "ins_s",
[6] = "loc_s",
[7] = "voc_s",
}
local input_params_to_slots_pl = {
[1] = "nom_p",
[2] = "gen_p",
[3] = "dat_p",
[4] = "acc_p",
[5] = "ins_p",
[6] = "loc_p",
[7] = "voc_p",
}
local cases = {
nom = true,
gen = true,
dat = true,
acc = true,
ins = true,
loc = true,
voc = true,
}
local accented_cases = {
["nóm"] = "nom",
["gén"] = "gen",
["dát"] = "dat",
["ácc"] = "acc",
["íns"] = "ins",
["lóc"] = "loc",
["vóc"] = "voc",
}
-- Stress patterns indicate where the stress goes for forms of each possible slot.
-- "-" means stem stress, "+" means ending stress. The field "stress" indicates
-- where to put the stem stress if the lemma doesn't include it. It applies primarily
-- to types d and f and variants of them. For example, lemma множина́ (type d) has
-- plural множи́ни (last-syllable stress), but lemma борода́ (type d') has plural
-- бо́роди (first-syllable stress).
local stress_patterns = {}
stress_patterns["a"] = {
nom_s="-", gen_s="-", dat_s="-", acc_s="-", ins_s="-", loc_s="-", voc_s="-",
nom_p="-", gen_p="-", dat_p="-", ins_p="-", loc_p="-", voc_p="-",
stress = nil,
}
stress_patterns["b"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="+", ins_s="+", loc_s="+", voc_s="+",
nom_p="+", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="+",
stress = "last",
}
stress_patterns["b'"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="+", ins_s="-", loc_s="+", voc_s="+",
nom_p="+", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="+",
stress = "last",
}
stress_patterns["c"] = {
nom_s="-", gen_s="-", dat_s="-", acc_s="-", ins_s="-", loc_s="-", voc_s="-",
nom_p="+", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="+",
stress = nil,
}
stress_patterns["d"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="+", ins_s="+", loc_s="+", voc_s="+",
nom_p="-", gen_p="-", dat_p="-", ins_p="-", loc_p="-", voc_p="-",
stress = "last",
}
stress_patterns["d'"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="-", ins_s="+", loc_s="+", voc_s="+",
nom_p="-", gen_p="-", dat_p="-", ins_p="-", loc_p="-", voc_p="-",
stress = "first",
}
stress_patterns["e"] = {
nom_s="-", gen_s="-", dat_s="-", acc_s="-", ins_s="-", loc_s="-", voc_s="-",
nom_p="-", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="-",
stress = nil,
}
stress_patterns["f"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="+", ins_s="+", loc_s="+", voc_s="+",
nom_p="-", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="-",
stress = "first",
}
stress_patterns["f'"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="-", ins_s="+", loc_s="+", voc_s="+",
nom_p="-", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="-",
stress = "first",
}
stress_patterns["f''"] = {
nom_s="+", gen_s="+", dat_s="+", acc_s="+", ins_s="-", loc_s="+", voc_s="+",
nom_p="-", gen_p="+", dat_p="+", ins_p="+", loc_p="+", voc_p="+",
stress = "first",
}
-- Maybe modify the stem and/or ending in certain special cases:
-- 1. Final -е in vocative singular triggers first palatalization of the stem
-- (except for hard nouns in -ц, like абзац and палац) and causes accent retraction
-- (except when base.no_retract_e, i.e. in neuters and soft feminines).
-- 2. Final -і in dative/locative singular triggers second palatalization.
local function apply_special_cases(base, slot, stem, ending)
if slot == "voc_s" and rfind(ending, "^е" .. accents_c .. "?$") then
if not base.no_palatalize_c or not rfind(stem, "ц$") then
stem = com.apply_first_palatalization(stem)
end
if ending == "е" and not base.no_retract_e then
ending = ending .. DOTUNDER
end
elseif (slot == "dat_s" or slot == "loc_s") and rfind(ending, "^і" .. accents_c .. "?$") then
stem = com.apply_second_palatalization(stem)
end
return stem, ending
end
local function skip_slot(number, slot)
return number == "sg" and rfind(slot, "_p$") or
number == "pl" and rfind(slot, "_s$")
end
local function add(base, slot, stress, endings, footnotes, explicit_stem)
if not endings then
return
end
-- Call skip_slot() based on the declined number; if the actual number is different, we correct this in
-- decline_noun() at the end.
if skip_slot(base.number, slot) then
return
end
footnotes = iut.combine_footnotes(iut.combine_footnotes(base.footnotes, stress.footnotes), footnotes)
if type(endings) == "string" then
endings = {endings}
end
local slot_is_plural = rfind(slot, "_p$")
local stress_for_slot
local stress_pattern_set = stress_patterns[stress.stress]
if not stress_pattern_set then
error("Internal error: Unrecognized stress pattern " .. stress.stress)
end
local stress_for_slot
if slot == "acc_p" then
-- This only applies when an override of acc_p is given.
if base.animacy == "inan" then
stress_for_slot = stress_pattern_set.nom_p
elseif base.animacy == "pr" then
stress_for_slot = stress_pattern_set.gen_p
elseif stress_pattern_set.nom_p == stress_pattern_set.gen_p then
stress_for_slot = stress_pattern_set.nom_p
else
for _, ending in ipairs(endings) do
if not rfind(ending, AC) and not rfind(ending, DOTUNDER) then
error("For animacy 'anml' and stress pattern " .. stress.stress .. ", must explicitly specify stress of override")
end
end
-- All endings have explicit stress, so it doesn't matter.
stress_for_slot = stress_pattern_set.nom_p
end
else
stress_for_slot = stress_pattern_set[slot]
if not stress_for_slot then
error("Internal error: Don't know stress for pattern " .. stress.stress .. ", slot " .. slot)
end
end
for _, ending in ipairs(endings) do
local stem
if explicit_stem then
stem = explicit_stem
else
if rfind(ending, "^ь?" .. com.vowel_c) then
stem = slot_is_plural and stress.pl_vowel_stem or stress.vowel_stem
else
stem = slot_is_plural and stress.pl_nonvowel_stem or stress.nonvowel_stem
end
end
stem, ending = apply_special_cases(base, slot, stem, ending)
if slot == "gen_p" and stress.genpl_reversed then
-- If end stress is called for, add it to the ending if possible, otherwise
-- go ahead and stress the last syllable of the stem.
if stress_for_slot ~= "+" then
if rfind(ending, com.vowel_c) then
ending = com.maybe_stress_initial_syllable(ending)
else
stem = com.remove_stress(stem)
stem = com.maybe_stress_final_syllable(stem)
end
end
elseif rfind(ending, DOTUNDER) then
-- DOTUNDER indicates stem stress in all cases
ending = rsub(ending, DOTUNDER, "")
elseif stress_for_slot == "+" then
ending = com.maybe_stress_initial_syllable(ending)
end
if com.is_nonsyllabic(stem) then
-- If stem is nonsyllabic, the ending must receive stress.
ending = com.maybe_stress_initial_syllable(ending)
end
ending = com.generate_form(ending, footnotes)
iut.add_forms(base.forms, slot, stem, ending, com.combine_stem_ending)
end
end
local function process_slot_overrides(base, do_slot)
for slot, overrides in pairs(base.overrides) do
-- Call skip_slot() based on the declined number; if the actual number is different, we correct this in
-- decline_noun() at the end.
if skip_slot(base.number, slot) then
error("Override specified for invalid slot '" .. slot .. "' due to '" .. base.number .. "' number restriction")
end
if do_slot(slot) then
base.forms[slot] = nil
local slot_is_plural = rfind(slot, "_p$")
for _, override in ipairs(overrides) do
for _, value in ipairs(override.values) do
local form = value.form
local combined_notes = iut.combine_footnotes(base.footnotes, value.footnotes)
if override.full then
if form:find("~") then
local stem
local ending = rsub(form, ".*~+", "")
if rfind(ending, "^ь?" .. com.vowel_c) then
stem = slot_is_plural and stress.pl_vowel_stem or stress.vowel_stem
else
stem = slot_is_plural and stress.pl_nonvowel_stem or stress.nonvowel_stem
end
if com.is_stressed(ending) then
stem = com.remove_stress(stem)
end
form = rsub(value, "~~~", com.apply_second_palatalization(stem))
form = rsub(value, "~~", com.apply_first_palatalization(stem))
form = rsub(value, "~", stem)
end
if form ~= "" then
iut.insert_form(base.forms, slot, {form = form, footnotes = combined_notes})
end
else
if override.stemstressed then
-- Signal not to add a stress to the ending even if the stress pattern
-- calls for it.
form = form .. DOTUNDER
end
for _, stress in ipairs(base.stresses) do
add(base, slot, stress, form, combined_notes)
end
end
end
end
end
end
end
local function add_decl(base, stress,
nom_s, gen_s, dat_s, acc_s, ins_s, loc_s, voc_s,
nom_p, gen_p, dat_p, ins_p, loc_p, footnotes
)
add(base, "nom_s", stress, nom_s, footnotes)
add(base, "gen_s", stress, gen_s, footnotes)
add(base, "dat_s", stress, dat_s, footnotes)
add(base, "acc_s", stress, acc_s, footnotes)
add(base, "ins_s", stress, ins_s, footnotes)
add(base, "loc_s", stress, loc_s, footnotes)
add(base, "voc_s", stress, voc_s, footnotes)
add(base, "nom_p", stress, nom_p, footnotes)
add(base, "gen_p", stress, gen_p, footnotes)
add(base, "dat_p", stress, dat_p, footnotes)
add(base, "ins_p", stress, ins_p, footnotes)
add(base, "loc_p", stress, loc_p, footnotes)
end
local function handle_derived_slots_and_overrides(base)
local function is_non_derived_slot(slot)
return slot ~= "voc_s" and slot ~= "voc_p" and slot ~= "acc_s" and slot ~= "acc_p"
end
local function is_derived_slot(slot)
return not is_non_derived_slot(slot)
end
-- Handle overrides for the non-derived slots. Do this before generating the derived
-- slots so overrides of the source slots (e.g. nom_p) propagate to the derived slots.
process_slot_overrides(base, is_non_derived_slot)
-- Generate the remaining slots that are derived from other slots.
iut.insert_forms(base.forms, "voc_p", base.forms["nom_p"])
if rfind(base.decl, "%-m$") or base.gender == "M" and base.decl == "adj" then
iut.insert_forms(base.forms, "acc_s", base.forms[base.animacy == "inan" and "nom_s" or "gen_s"])
end
local function tag_with_variant(variant)
return function(form) return form .. variant end
end
local function maybe_tag_with_variant(forms, variant)
if base.multiword then
return iut.map_forms(forms, tag_with_variant(variant))
else
return forms
end
end
if base.animacy == "inan" then
iut.insert_forms(base.forms, "acc_p", base.forms["nom_p"])
elseif base.animacy == "pr" then
iut.insert_forms(base.forms, "acc_p", base.forms["gen_p"])
elseif base.animacy == "anml" then
iut.insert_forms(base.forms, "acc_p", maybe_tag_with_variant(base.forms["nom_p"], com.VAR1))
iut.insert_forms(base.forms, "acc_p", maybe_tag_with_variant(base.forms["gen_p"], com.VAR2))
else
error("Internal error: Unrecognized animacy: " .. (base.animacy or "nil"))
end
if base.surname then
iut.insert_forms(base.forms, "voc_s", base.forms["nom_s"])
end
-- Handle overrides for derived slots, to allow them to be overridden.
process_slot_overrides(base, is_derived_slot)
-- Compute linked versions of potential lemma slots, for use in {{uk-noun}}.
-- We substitute the original lemma (before removing links) for forms that
-- are the same as the lemma, if the original lemma has links.
for _, slot in ipairs({"nom_s", "nom_p"}) do
iut.insert_forms(base.forms, slot .. "_linked", iut.map_forms(base.forms[slot], function(form)
if form == base.orig_lemma_no_links and rfind(base.orig_lemma, "%[%[") then
return base.orig_lemma
else
return form
end
end))
end
end
local decls = {}
local declprops = {}
local function default_genitive_u(base)
return (base.number == "sg" or base.usuallysg) and not rfind(base.lemma, "^" .. com.uppercase_c)
end
decls["hard-m"] = function(base, stress)
base.no_palatalize_c = true
local velar = rfind(stress.vowel_stem, com.velar_c .. "$")
local gen_s = default_genitive_u(base) and "у" or "а" -- may be overridden
local loc_s =
-- these conditions seem weird but it's what I observed
velar and (base.animacy ~= "inan" or stress.reducible) and {"ові", "у"} or
velar and "у" or
base.animacy ~= "inan" and {"ові", "і"} or
(base.number == "sg" or base.usuallysg) and {"у", "і"} or
"і"
local voc_s =
-- these conditions also seem weird but it's what I observed
velar and base.animacy == "anml" and stress.stress == "b" and "е" or
velar and "у" or
"е"
-- handle soft stem ending in vowel (хазя́їн, pl. хазяї́;
-- зуб "tooth, cog" alt nom pl. зу́б'я, gen pl зу́б'їв)
local plvowel = com.ends_in_vowel(stress.pl_vowel_stem) or rfind(stress.pl_vowel_stem, "'$")
local gen_p = base.remove_in and "" or plvowel and "їв" or "ів"
add_decl(base, stress, "", gen_s, {"ові", "у"}, nil, "ом", loc_s, voc_s)
if base.plsoft then
local nom_p = plvowel and "ї" or "і"
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
nom_p, gen_p, "ям", "ями", "ях")
else
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
"и", gen_p, "ам", "ами", "ах")
end
end
declprops["hard-m"] = {
desc = function(base, stress)
if rfind(stress.vowel_stem, com.velar_c .. "$") then
return "velar masc-form"
else
return "hard masc-form"
end
end,
cat = function(base, stress)
if rfind(stress.vowel_stem, com.velar_c .. "$") then
return "velar-stem masculine-form"
else
return "hard masculine-form"
end
end
}
decls["semisoft-m"] = function(base, stress)
local gen_s = default_genitive_u(base) and "у" or "а" -- may be overridden
local loc_s = base.animacy ~= "inan" and {"еві", "у", "і"} or {"у", "і"}
-- FIXME: Should vocative singular in -у be end-stressed if reducible, parallel
-- to soft nouns? I don't have any examples of reducible nouns in -ч, ш or щ.
local voc_s = rfind(stress.vowel_stem, "[рж]$") and "е" or "у̣" -- dot underneath у
add_decl(base, stress, "", gen_s, {"еві", "у"}, nil, "ем", loc_s, voc_s,
"і", "ів", "ам", "ами", "ах")
end
declprops["semisoft-m"] = {
desc = "ဗီုပြၚ်ပုလ္လိၚ်မဍိုန်မွဲကဝက်",
cat = "ဗီုပြၚ်ပုလ္လိၚ်မဍိုန်မွဲကဝက်",
}
decls["soft-m"] = function(base, stress)
local nom_s = rfind(stress.nonvowel_stem, "р$") and "" or "ь"
local gen_s = default_genitive_u(base) and "ю" or "я" -- may be overridden
local loc_s = base.animacy ~= "inan" and {"еві", "ю", "і"} or {"ю", "і"}
-- More weird conditions: vocative singular in accent b is end-stressed if
-- reducible or ending in -інь (from Proto-Slavic nouns in -y), stem-stressed
-- otherwise.
local voc_s = (stress.reducible or (
rfind(stress.nonvowel_stem, "і́?н$") and rfind(stress.vowel_stem, "е́?н$")
)) and "ю" or "ю̣"
add_decl(base, stress, nom_s, gen_s, {"еві", "ю"}, nil, "ем", loc_s, voc_s,
"і", "ів", "ям", "ями", "ях")
end
declprops["soft-m"] = {
desc = "ဗီုပြၚ်ပုလ္လိၚ်မဍိုန်",
cat = "ဗီုပြၚ်ပုလ္လိၚ်မဍိုန်",
}
decls["j-m"] = function(base, stress)
local gen_s = default_genitive_u(base) and "ю" or "я" -- may be overridden
local loc_s = base.animacy ~= "inan" and {"ю", "єві", "ї"} or {"ю", "ї"}
-- As with soft nouns, vocative singular in accent b is end-stressed if
-- reducible, stem-stressed otherwise.
local voc_s = stress.reducible and "ю" or "ю̣"
add_decl(base, stress, "й", gen_s, {"ю", "єві"}, nil, "єм", loc_s, voc_s,
"ї", "їв", "ям", "ями", "ях")
end
declprops["j-m"] = {
desc = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်ပုလ္လိၚ်",
cat = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်ပုလ္လိၚ်",
}
decls["o-m"] = function(base, stress)
local unstressed_lo =
rfind(stress.vowel_stem, "л$") and stress_patterns[stress.stress].nom_s == "-"
local velar = rfind(stress.vowel_stem, com.velar_c .. "$")
local hushing = rfind(stress.vowel_stem, com.hushing_c .. "$")
local loc_s =
-- these conditions are partly based on analogy with the neuter;
-- masculines in -о (not counting proper names):
-- (1) in -ко: ба́тько "father", дя́дько "uncle", "сонько́" (MF) "sleepyhead",
-- солове́йко "nightingale"
-- (2) in -ьо: дя́дьо "uncle", не́ньо "dad";
-- (3) in -то, -до: та́то "dad";
-- (4) in vowel + -ло: громи́ло "bully, thug", зубри́ло "rote memorizer, mechanical studier",
-- чуди́ло "eccentric person, kook, weirdo", бурми́ло "clumsy person, oaf, klutz",
-- страши́ло/страши́дло "scary monster" (MN), базі́кало "chatterbox, braggart" (MN)
-- (5) in cons + -ло: міня́йло "moneychanger" (N per sum.in.ua, M per Horokh,
-- mova.info and Slovnyk), вайло́ "clumsy person, oaf, klutz" (M per Horokh and
-- Slovnyk's declension table, MF per sum.in.ua, MN per mova.info),
-- трепло́ "chatterbox, braggart" (N or M per Horokh, N only per other sources)
-- (6) in -що: леда́що "lazy person, sluggard" (MN)
-- (7) in -и́сько: хлопчи́сько "boy" (MN), пани́сько "nasty sir", бідачи́сько "wretched man" (MN),
-- чорти́сько "big devil", діди́сько "large/nasty grandfather?", попи́сько "nasty priest",
-- парубчи́сько "young man (pej.)", простачи́сько "simpleton?" (all personal);
-- вовчи́сько "large wolf", коти́сько "large cat", пси́сько "large dog", барани́сько "large ram",
-- бичи́сько "large bull", кабани́сько "large boar", соми́сько "large catfish", кони́сько "large horse",
-- etc. (animal); чуби́сько "large forehead", вітри́сько "big wind?", голоси́сько "big voice",
-- хвости́сько "large tail", кожуши́сько "big fur coat", ножи́сько "big knife?",
-- тютюни́сько "nasty tobacco", чоботи́сько "large boot" (pl. чоботи́ська),
-- хліби́сько "large bread/loaf", батожи́сько "?",etc.
velar and base.animacy ~= "inan" and {"ові", "у"} or
hushing and base.animacy ~= "inan" and {"еві", "у", "і"} or
velar and "у" or
hushing and {"у", "і"} or
base.animacy ~= "inan" and {"ові", "і"} or
"і"
local ins_s = hushing and "ем" or "ом"
local voc_s =
velar and base.animacy ~= "inan" and "у" or
(unstressed_lo or (hushing and base.animacy ~= "inan")) and "е" or
"о"
add_decl(base, stress, "о", "а", {"ові", "у"}, nil, ins_s, loc_s, voc_s,
unstressed_lo and "а" or "и", unstressed_lo and "" or "ів", "ам", "ами", "ах")
end
local function get_stem_type(stress)
if rfind(stress.vowel_stem, com.velar_c .. "$") then
return "velar-stem"
elseif rfind(stress.vowel_stem, com.hushing_c .. "$") then
return "semisoft"
else
return "hard"
end
end
local function o_m_desc(base, stress, soft)
local gender
if base.gender == "M" then
gender = "masc"
elseif base.gender == "MF" then
gender = "masc/fem"
elseif base.gender == "F" then
gender = "fem"
else
error("Internal error: Bad gender '" .. base.gender .. "' for o-m type")
end
return (soft and "soft" or rsub(get_stem_type(stress), "%-stem$", "")) .. " " .. gender .. " in -о"
end
local function o_m_cat(base, stress, soft)
local stem_type = soft and "soft" or get_stem_type(stress)
local cats = {}
if base.gender == "M" or base.gender == "MF" then
-- table.insert(cats, stem_type .. " masculine nouns in -о")
-- table.insert(cats, stem_type .. " masculine ~ nouns in -о")
end
if base.gender == "F" or base.gender == "MF" then
-- table.insert(cats, stem_type .. " feminine nouns in -о")
-- table.insert(cats, stem_type .. " feminine ~ nouns in -о")
end
return cats
end
declprops["o-m"] = {
desc = o_m_desc,
cat = o_m_cat,
}
decls["soft-o-m"] = function(base, stress)
add_decl(base, stress, "ьо", "я", {"еві", "ю"}, nil, "ем", {"еві", "ю", "і"}, "ю",
"і", "ів", "ям", "ями", "ях")
end
declprops["soft-o-m"] = {
desc = function(base, stress) return o_m_desc(base, stress, "soft") end,
cat = function(base, stress) return o_m_cat(base, stress, "soft") end,
}
decls["semisoft-e-m"] = function(base, stress)
base.no_retract_e = true
-- Known examples: вовчи́ще "big wolf" (animate), діди́ще "big grandfather",
-- дружи́ще "old buddy, pal, chap" (animate);
-- вітри́ще "big wind", доми́ще "big house" (also N per mova.info), кулачи́ще "big fist" (MN),
-- замчи́ще/за́мчище "large castle; site of former castle" (MN) (inanimate)
-- The animate values are based only on баби́ще but have parallels in
-- semisoft masculine nouns.
local dat_s =
base.animacy ~= "inan" and {"еві", "у"} or
"у"
local loc_s =
base.animacy ~= "inan" and {"еві", "у", "і"} or
{"у", "і"}
add_decl(base, stress, "е", "а", dat_s, "е", "ем", loc_s, "е",
"а", "", "ам", "ами", "ах")
end
declprops["semisoft-e-m"] = {
desc = "ပုလ္လိၚ်မဍိုန်မွဲကဝက်ပ္ဍဲ -е",
cat = {"နာမ်ပုလ္လိၚ်မဍိုန်မွဲကဝက်ပ္ဍဲ -е", "ပုလ္လိၚ်မဍိုန်မွဲကဝက် ~ နာမ်ပ္ဍဲ -е"},
}
decls["hard-f"] = function(base, stress)
base.no_palatalize_c = true
-- Vocative singular in stress pattern b is end-stressed; stem-stressed otherwise.
local voc_sg = stress.stress == "b" and "о" or "о̣"
add_decl(base, stress, "а", "и", "і", "у", "ою", "і", voc_sg)
if base.plsoft then
-- люди́на, дити́на
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
"и", "ей", "ям", "ями", "ях")
else
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
"и", "", "ам", "ами", "ах")
end
end
declprops["hard-f"] = {
desc = "ဗီုပြၚ်ဣတ္တိလိၚ်မဗိုန်ဂြတ်",
cat = "ဗီုပြၚ်ဣတ္တိလိၚ်မဗိုန်ဂြတ်",
}
decls["semisoft-f"] = function(base, stress)
add_decl(base, stress, "а", "і", "і", "у", "ею", "і", "е",
"і", "", "ам", "ами", "ах")
end
declprops["semisoft-f"] = {
desc = "ဗီုပြၚ်ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်",
cat = "ဗီုပြၚ်ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်",
}
decls["soft-f"] = function(base, stress)
base.no_retract_e = true
base.no_palatalize_c = true
local voc_s = rfind(stress.vowel_stem, "у́с$") and "ю" or -- бабу́ся, мату́ся, ду́ся, Катру́ся, etc.
"е"
add_decl(base, stress, "я", "і", "і", "ю", "ею", "і", voc_s,
"і", rfind(stress.pl_nonvowel_stem, "[сздтлнц]$") and "ь" or "", "ям", "ями", "ях")
end
declprops["soft-f"] = {
desc = "ဗီုပြၚ်ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်",
cat = "ဗီုပြၚ်ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်",
}
decls["j-f"] = function(base, stress)
base.no_retract_e = true
add_decl(base, stress, "я", "ї", "ї", "ю", "єю", "ї", "є",
"ї", "й", "ям", "ями", "ях")
end
declprops["j-f"] = {
desc = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်ဣတ္တိလိၚ်",
cat = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်ဣတ္တိလိၚ်",
}
decls["third-f"] = function(base, stress)
base.no_retract_e = true
local nom_sg = rfind(stress.nonvowel_stem, "[сздтлнц]$") and "ь" or ""
-- All third-decl feminine nouns ending in -Cть appear to have two possible genitive
-- singulars, at least per the current orthography. Some other third-decl nouns (о́сінь "autumn",
-- сіль "salt" and кров "blood") behave the same way, but most don't.
local gen_sg = rfind(stress.vowel_stem, "[^аеєиіїоуюяАЕЄИІЇОУЮЯ́ ]т$") and {"і", "и"} or "і"
local hushing = rfind(stress.vowel_stem, "[чшжщ]$")
local plvowel = hushing and "а" or "я"
add_decl(base, stress, nom_sg, gen_sg, "і", nom_sg, nil, "і", "е",
"і", "ей", plvowel .. "м", plvowel .. "ми", plvowel .. "х")
local ins_s_stem = stress.nonvowel_stem
local pre_stem, final_cons = rmatch(ins_s_stem, "^(.*)([сздтлнцчшжщ])$")
if pre_stem then
if rfind(pre_stem, com.vowel_c .. AC .. "?$") then
-- vowel + doublable cons; double the cons
ins_s_stem = ins_s_stem .. final_cons
end
-- if non-vowel + doublable cons, don't change stem,
-- e.g. смерть -> ins sg сме́ртю
else
ins_s_stem = ins_s_stem .. "'"
end
add(base, "ins_s", stress, "ю", nil, ins_s_stem)
end
declprops["third-f"] = {
desc = "ဗီုပြၚ်ဣတ္တိလိၚ်မလဟုတ်စှ်ေမရနုက်ကဵု၃",
cat = "ဗီုပြၚ်ဣတ္တိလိၚ်မလဟုတ်စှ်ေမရနုက်ကဵု၃",
}
decls["semisoft-e-f"] = function(base, stress)
-- at least баби́ще (which can also be neuter, with neuter declension)
base.no_retract_e = true
add_decl(base, stress, "е", "і", "і", "е", "ею", "і", "е",
"і", "", "ам", "ами", "ах")
end
declprops["semisoft-e-f"] = {
desc = "ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်ပ္ဍဲ -е",
cat = {"နာမ်ဣတ္တိလိၚ်မဍိုန်မွဲကဝက်ပ္ဍဲ -е", "ဣတ္တိလိၚ်မဍိုန်မွဲကဝက် ~ နာမ်ပ္ဍဲ -е"},
}
decls["hard-n"] = function(base, stress)
base.no_retract_e = true
base.no_palatalize_c = true
local velar = rfind(stress.vowel_stem, com.velar_c .. "$")
-- Dictionaries disagree on whether neuter animates have -о or -а in the
-- accusative singular. Both appear possible, with -о maybe more common.
-- Neuter animates in -е appear to always have -е in the accusative singular.
local acc_s = base.animacy ~= "inan" and {"о", "а"} or "о"
-- All neuter animates appear to have dative singular in -ові/-у; several
-- neuter inanimates do too, but the majority appear to have just -у
local dat_s = base.animacy ~= "inan" and {"ові", "у"} or "у"
local loc_s =
-- these conditions are partly based on analogy with the masculine (including o-m);
-- neuter animates:
-- animal: со́нечко "ladybug", риби́сько "big fish", густя́ко "goose (endearing diminutive)",
-- чу́до "fabulous creature", чудо́висько "monster (animal)";
-- personal: ча́до "child" (archaic/jocular), ла́до "beloved, darling"
-- (when referring to a child), дівчи́сько "girl", баби́сько "nasty grandmother",
-- діти́ська (pl.) "children"
velar and base.animacy ~= "inan" and {"ові", "у"} or
velar and "у" or
base.animacy ~= "inan" and {"ові", "і"} or
"і"
local voc_s =
velar and base.animacy ~= "inan" and "у" or
"о"
add_decl(base, stress, "о", "а", dat_s, acc_s, "ом", loc_s, voc_s,
"а", "", "ам", "ами", "ах")
end
declprops["hard-n"] = {
desc = function(base, stress)
if rfind(stress.vowel_stem, com.velar_c .. "$") then
return "velar neut-form"
else
return "hard neut-form"
end
end,
cat = function(base, stress)
if rfind(stress.vowel_stem, com.velar_c .. "$") then
return "velar-stem neuter-form"
else
return "hard neuter-form"
end
end
}
decls["semisoft-n"] = function(base, stress)
base.no_retract_e = true
-- The animate values are based only on баби́ще but have parallels in
-- semisoft masculine nouns. (страхо́вище?)
local dat_s =
base.animacy ~= "inan" and {"еві", "у"} or
"у"
local loc_s =
base.animacy ~= "inan" and {"еві", "у", "і"} or
{"у", "і"}
add_decl(base, stress, "е", "а", dat_s, "е", "ем", loc_s, "е",
"а", "", "ам", "ами", "ах")
end
declprops["semisoft-n"] = {
desc = "ဗီုပြၚ်နပုလ္လိၚ်မဍိုန်မွဲကဝက်",
cat = "ဗီုပြၚ်နပုလ္လိၚ်မဍိုန်မွဲကဝက်",
}
decls["soft-n"] = function(base, stress)
base.no_retract_e = true
add_decl(base, stress, "е", "я", "ю", "е", "ем", {"ю", "і"}, "е",
"я", rfind(stress.pl_nonvowel_stem, "[сздтлнц]$") and "ь" or "", "ям", "ями", "ях")
end
declprops["soft-n"] = {
desc = "ဗီုပြၚ်နပုလ္လိၚ်မဍိုန်",
cat = "ဗီုပြၚ်နပုလ္လိၚ်မဍိုန်",
}
decls["j-n"] = function(base, stress)
base.no_retract_e = true
add_decl(base, stress, "є", "я", "ю", "є", "єм", {"ю", "ї"}, "є",
"я", "й", "ям", "ями", "ях")
end
declprops["j-n"] = {
desc = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်နပုလ္လိၚ်",
cat = "တံမအရေဝ် (ဇ်/j) ဗီုပြၚ်နပုလ္လိၚ်",
}
decls["ja-n"] = function(base, stress)
local loc_sg = rfind(stress.vowel_stem, "['й]$") and "ї" or "і"
if stress_patterns[stress.stress].loc_sg == "-" then
loc_sg = {"ю", loc_sg}
end
local gen_pl_end_stressed = stress_patterns[stress.stress].gen_pl == "+"
add_decl(base, stress, "я", "я", "ю", "я", "ям", loc_sg, "я")
if base.plhard then
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
"а", gen_pl_end_stressed and "ів" or "", "ам", "ами", "ах")
else
local gen_pl =
rfind(stress.pl_vowel_stem, "['й]$") and "їв" or
gen_pl_end_stressed and "ів" or
rfind(stress.pl_nonvowel_stem, "[сздтлнц]$") and "ь" or
""
add_decl(base, stress, nil, nil, nil, nil, nil, nil, nil,
"я", gen_pl, "ям", "ями", "ях")
end
end
declprops["ja-n"] = {
desc = "နပုလ္လိၚ်ပ္ဍဲ (ဇ/ja)",
cat = {"နာမ်နပုလ္လိၚ်မဍိုန်ပ္ဍဲ -я", "နပုလ္လိၚ်မဍိုန် ~ နာမ်ပ္ဍဲ -я"},
}
decls["en-n"] = function(base, stress)
decls["ja-n"](base, stress)
local n_stem = rsub(stress.vowel_stem, "'$", "ен")
add(base, "gen_s", stress, "і", nil, n_stem)
add(base, "dat_s", stress, "і", nil, n_stem)
add(base, "ins_s", stress, "ем", nil, n_stem)
add(base, "loc_s", stress, "і", nil, n_stem)
end
declprops["en-n"] = {
desc = "တံမအရေဝ် (န်/n) ဗီုပြၚ်နပုလ္လိၚ်",
cat = "တံမအရေဝ် (န်/n) ဗီုပြၚ်နပုလ္လိၚ်",
}
decls["t-n"] = function(base, stress)
-- Most t-stem neuters end in -я́, but there's also лоша́, курча́, двіча́, ...
local v = rfind(stress.vowel_stem, com.hushing_c .. "$") and "а" or "я"
add_decl(base, stress, v, v .. "ти", v .. "ті", v, v .. "м", v .. "ті", v,
v .. "та", v .. "т", v .. "там", v .. "тами", v .. "тах")
end
declprops["t-n"] = {
desc = "တံမအရေဝ် (တ်/t) ဗီုပြၚ်နပုလ္လိၚ်",
cat = "တံမအရေဝ် (တ်/t) ဗီုပြၚ်နပုလ္လိၚ်",
}
decls["adj"] = function(base, stress)
local props = {}
if base.ialt then
table.insert(props, base.ialt)
end
if base.surname then
table.insert(props, "surname")
end
local propspec = table.concat(props, ".")
if propspec ~= "" then
propspec = "<" .. propspec .. ">"
end
local adj_alternant_multiword_spec = require("Module:uk-adjective").do_generate_forms({base.lemma .. propspec})
local function copy(from_slot, to_slot)
base.forms[to_slot] = adj_alternant_multiword_spec.forms[from_slot]
end
if base.number ~= "pl" then
if base.gender == "M" then
copy("nom_m", "nom_s")
copy("gen_m", "gen_s")
copy("dat_m", "dat_s")
copy("ins_m", "ins_s")
copy("loc_m", "loc_s")
copy("voc_m", "voc_s")
elseif base.gender == "F" then
copy("nom_f", "nom_s")
copy("gen_f", "gen_s")
copy("dat_f", "dat_s")
copy("acc_f", "acc_s")
copy("ins_f", "ins_s")
copy("loc_f", "loc_s")
copy("voc_f", "voc_s")
elseif base.gender == "N" then
copy("nom_n", "nom_s")
copy("gen_m", "gen_s")
copy("dat_m", "dat_s")
copy("acc_n", "acc_s")
copy("ins_m", "ins_s")
copy("loc_m", "loc_s")
copy("voc_n", "voc_s")
else
error("Internal error: Unrecognized gender: " .. base.gender)
end
if not base.forms.voc_s then
iut.insert_forms(base.forms, "voc_s", base.forms["nom_s"])
end
end
if base.number ~= "sg" then
copy("nom_p", "nom_p")
copy("gen_p", "gen_p")
copy("dat_p", "dat_p")
copy("ins_p", "ins_p")
copy("loc_p", "loc_p")
end
end
declprops["adj"] = {
desc = function(base, stress)
if base.number == "pl" then
return "adj"
elseif base.gender == "M" then
return "adj masc"
elseif base.gender == "F" then
return "adj fem"
elseif base.gender == "N" then
return "adj neut"
else
error("Internal error: Unrecognized gender: " .. base.gender)
end
end,
cat = function(base, stress)
local gender
if base.number == "pl" then
gender = "plural-only"
elseif base.gender == "M" then
gender = "masculine"
elseif base.gender == "F" then
gender = "feminine"
elseif base.gender == "N" then
gender = "neuter"
else
error("Internal error: Unrecognized gender: " .. base.gender)
end
local stemtype
if rfind(base.lemma, "ци́?й$") then
stemtype = "c-stem"
elseif rfind(base.lemma, "и́?й$") then
stemtype = "hard"
elseif rfind(base.lemma, "і́?й$") then
stemtype = "soft"
elseif rfind(base.lemma, "ї́?й$") then
stemtype = "j-stem"
elseif base.surname then
stemtype = "surname"
else
stemtype = "possessive"
end
return {"adjectival nouns", stemtype .. " " .. gender .. " adjectival ~ nouns"}
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
--[=[
Parse a single override spec (e.g. 'loci:ú' or 'datpl:чо́ботам:чобо́тям[rare]') and return
two values: the slot the override applies to, and an object describing the override spec.
The input is actually a list where the footnotes have been separated out; for example,
given the spec 'inspl:чо́ботами:чобо́тями[rare]:чобітьми́[archaic]', the input will be a list
{"inspl:чо́ботами:чобо́тями", "[rare]", ":чобітьми́", "[archaic]", ""}. The object returned
for 'datpl:чо́ботам:чобо́тям[rare]' looks like this:
{
full = true,
values = {
{
form = "чо́ботам"
},
{
form = "чобо́тям",
footnotes = {"[rare]"}
}
}
}
The object returned for 'lócji:jú' looks like this:
{
stemstressed = true,
values = {
{
form = "ї",
},
{
form = "ю́",
}
}
}
Note that all forms (full or partial) are reverse-transliterated, and full forms are
normalized by adding an accent to monosyllabic forms.
]=]
local function parse_override(segments)
local retval = {values = {}}
local part = segments[1]
local case = usub(part, 1, 3)
if cases[case] then
-- ok
elseif accented_cases[case] then
case = accented_cases[case]
retval.stemstressed = true
else
error("Internal error: unrecognized case in override: '" .. table.concat(segments) .. "'")
end
local rest = usub(part, 4)
local slot
if rfind(rest, "^pl") then
rest = rsub(rest, "^pl", "")
slot = case .. "_p"
else
slot = case .. "_s"
end
if rfind(rest, "^:") then
retval.full = true
rest = rsub(rest, "^:", "")
end
segments[1] = rest
local colon_separated_groups = put.split_alternating_runs(segments, ":")
for i, colon_separated_group in ipairs(colon_separated_groups) do
local value = {}
local form = colon_separated_group[1]
if form == "" then
error("Use - to indicate an empty ending for slot '" .. slot .. "': '" .. table.concat(segments .. "'"))
elseif form == "-" then
value.form = ""
else
value.form = m_uk_translit.reverse_tr(form)
if retval.full then
value.form = com.add_monosyllabic_stress(value.form)
if com.needs_accents(value.form) then
error("Override '" .. value.form .. "' for slot '" .. slot .. "' missing an accent")
end
end
end
value.footnotes = fetch_footnotes(colon_separated_group)
table.insert(retval.values, value)
end
return slot, retval
end
--[=[
Parse an indicator spec (text consisting of angle brackets and zero or more
dot-separated indicators within them). Return value is an object of the form
{
overrides = {
SLOT = {OVERRIDE, OVERRIDE, ...}, -- as returned by parse_override()
...
},
forms = {}, -- forms for a single spec alternant; see `forms` below
footnotes = {"FOOTNOTE", "FOOTNOTE", ...}, -- may be missing
stresses = { -- may be missing
{
stress = "STRESS", -- "a", "b", etc.
reducible = TRUE_OR_FALSE,
genpl_reversed = TRUE_OR_FALSE,
footnotes = {"FOOTNOTE", "FOOTNOTE", ...}, -- may be missing
-- The following fields are filled in by determine_stress_and_stems()
vowel_stem = "STEM",
nonvowel_stem = "STEM",
pl_vowel_stem = "STEM",
pl_nonvowel_stem = "STEM",
},
...
},
explicit_gender = "GENDER", -- "M", "F", "N", "MF"; may be missing
number = "NUMBER", -- "sg", "pl"; may be missing
animacy = "ANIMACY", -- "inan", "anml", "pr"; may be missing
ialt = "VOWEL_ALTERNATION", -- "i", "ie", "ijo", "io"; may be missing
rtype = "RTYPE", -- "soft", "semisoft"; may be missing
neutertype = "NEUTERTYPE", -- "t", "en"; may be missing
plsoft = true, -- may be missing
plhard = true, -- may be missing
remove_in = true, -- may be missing
thirddecl = true, -- may be missing
surname = true, -- may be missing
adj = true, -- may be missing
stem = "STEM", -- may be missing
plstem = "PLSTEM", -- may be missing
declnumber = "DECLENSION-NUMBER", -- may be missing
-- The following additional fields are added by other functions:
orig_lemma = "ORIGINAL-LEMMA", -- as given by the user
orig_lemma_no_links = "ORIGINAL-LEMMA-NO-LINKS", -- links removed, monosyllabic stress added
lemma = "LEMMA", -- `orig_lemma_no_links`, converted to singular form if plural
forms = {
SLOT = {
{
form = "FORM",
footnotes = {"FOOTNOTE", "FOOTNOTE", ...} -- may be missing
},
...
},
...
},
decl = "DECL", -- declension, e.g. "hard-m"
vowel_stem = "VOWEL-STEM", -- derived from vowel-ending lemmas
nonvowel_stem = "NONVOWEL-STEM", -- derived from non-vowel-ending lemmas
}
]=]
local function parse_indicator_spec(angle_bracket_spec)
local inside = rmatch(angle_bracket_spec, "^<(.*)>$")
assert(inside)
local base = {overrides = {}, forms = {}}
if inside ~= "" then
local segments = put.parse_balanced_segment_run(inside, "[", "]")
local dot_separated_groups = put.split_alternating_runs(segments, "%.")
for i, dot_separated_group in ipairs(dot_separated_groups) do
local part = dot_separated_group[1]
local case_prefix = usub(part, 1, 3)
if cases[case_prefix] or accented_cases[case_prefix] then
local slot, override = parse_override(dot_separated_group)
if base.overrides[slot] then
table.insert(base.overrides[slot], override)
else
base.overrides[slot] = {override}
end
elseif part == "" then
if #dot_separated_group == 1 then
error("Blank indicator: '" .. inside .. "'")
end
base.footnotes = fetch_footnotes(dot_separated_group)
elseif rfind(part, "^[a-f]'*[*#]*$") or rfind(part, "^[a-f]'*[*#]*,") or
rfind(part, "^[*#]*$") or rfind(part, "^[*#]*,") then
if base.stresses then
error("Can't specify stress pattern indicator twice: '" .. inside .. "'")
end
local comma_separated_groups = put.split_alternating_runs(dot_separated_group, ",")
local patterns = {}
for i, comma_separated_group in ipairs(comma_separated_groups) do
local pattern = comma_separated_group[1]
local pat, reducible = rsubb(pattern, "%*", "")
local genpl_reversed
pat, genpl_reversed = rsubb(pat, "#", "")
if pat == "" then
pat = nil
end
if pat and not stress_patterns[pat] then
error("Unrecognized stress pattern '" .. pat .. "': '" .. inside .. "'")
end
table.insert(patterns, {
stress = pat, reducible = reducible, genpl_reversed = genpl_reversed,
footnotes = fetch_footnotes(comma_separated_group)
})
end
base.stresses = patterns
elseif #dot_separated_group > 1 then
error("Footnotes only allowed with slot overrides, stress patterns or by themselves: '" .. table.concat(dot_separated_group) .. "'")
elseif part == "M" or part == "MF" or part == "F" or part == "N" then
if base.explicit_gender then
error("Can't specify gender twice: '" .. inside .. "'")
end
base.explicit_gender = part
elseif part == "sg" or part == "sg+" or part == "pl" or part == "both" then
if base.number then
error("Can't specify number twice: '" .. inside .. "'")
elseif part == "sg+" then
base.number = "both"
base.usuallysg = true
else
base.number = part
end
elseif part == "pr" or part == "anml" or part == "inan" then
if base.animacy then
error("Can't specify animacy twice: '" .. inside .. "'")
end
base.animacy = part
elseif part == "i" or part == "io" or part == "ijo" or part == "ie" then
if base.ialt then
error("Can't specify і-alternation indicator twice: '" .. inside .. "'")
end
base.ialt = part
elseif part == "soft" or part == "semisoft" then
if base.rtype then
error("Can't specify 'р' type ('soft' or 'semisoft') more than once: '" .. inside .. "'")
end
base.rtype = part
elseif part == "t" or part == "en" then
if base.neutertype then
error("Can't specify neuter indicator ('t' or 'en') more than once: '" .. inside .. "'")
end
base.neutertype = part
elseif part == "plsoft" then
if base.plsoft then
error("Can't specify 'plsoft' twice: '" .. inside .. "'")
end
base.plsoft = true
elseif part == "plhard" then
if base.plhard then
error("Can't specify 'plhard' twice: '" .. inside .. "'")
end
base.plhard = true
elseif part == "in" then
if base.remove_in then
error("Can't specify 'in' twice: '" .. inside .. "'")
end
base.remove_in = true
elseif part == "3rd" then
if base.thirddecl then
error("Can't specify '3rd' twice: '" .. inside .. "'")
end
base.thirddecl = true
elseif part == "surname" then
if base.surname then
error("Can't specify 'surname' twice: '" .. inside .. "'")
end
base.surname = true
elseif part == "+" then
if base.adj then
error("Can't specify '+' twice: '" .. inside .. "'")
end
base.adj = true
elseif rfind(part, "^stem:") then
if base.stem then
error("Can't specify stem twice: '" .. inside .. "'")
end
base.stem = rsub(part, "^stem:", "")
elseif rfind(part, "^plstem:") then
if base.plstem then
error("Can't specify plural stem twice: '" .. inside .. "'")
end
base.plstem = rsub(part, "^plstem:", "")
elseif rfind(part, "^declnumber:") then
if base.declnumber then
error("Can't specify 'declnumber:' twice: '" .. inside .. "'")
end
base.declnumber = rsub(part, "^declnumber:", "")
else
error("Unrecognized indicator '" .. part .. "': '" .. inside .. "'")
end
end
end
return base
end
local function add_stress_for_pattern(stress, stem)
local where_stress = stress_patterns[stress.stress].stress
if where_stress == "last" then
return com.maybe_stress_final_syllable(stem)
elseif where_stress == "first" then
return com.maybe_stress_initial_syllable(stem)
elseif not com.is_stressed(stem) then
error("Something wrong: Stress pattern " .. stress.stress .. " but stem '" .. stem .. "' doesn't have stress")
else
return stem
end
end
local function process_declnumber(base)
base.actual_number = base.number
if base.declnumber then
if base.declnumber == "sg" or base.declnumber == "pl" or base.declnumber == "both" then
base.number = base.declnumber
else
error(("Unrecognized value '%s' for 'declnumber', should be 'sg', 'pl' or 'both'"):format(base.declnumber))
end
end
end
local function set_defaults_and_check_bad_indicators(base)
-- Set default values.
if not base.adj then
base.number = base.number or "both"
base.usuallysg = base.usuallysg or false
process_declnumber(base)
base.animacy = base.animacy or base.surname and "pr" or
base.neutertype == "t" and "anml" or
"inan"
end
base.gender = base.explicit_gender
-- Set some further defaults and check for certain bad indicator/number/gender combinations.
if base.thirddecl then
if base.number ~= "pl" then
error("'3rd' can only be specified along with 'pl'")
end
if base.gender and base.gender ~= "F" then
error("'3rd' can't specified with non-feminine gender indicator '" .. base.gender .. "'")
end
base.gender = "F"
end
if base.neutertype then
if base.gender and base.gender ~= "N" then
error("Neuter-type indicator '" .. base.neutertype .. "' can't specified with non-neuter gender indicator '" .. base.gender .. "'")
end
base.gender = "N"
end
end
local function undo_vowel_alternation(base, stem)
if base.ialt == "io" then
local modstem = rsub(stem, "([оО])(́?" .. com.cons_c .. "*)$",
function(vowel, post)
if vowel == "о" then
return "і" .. post
else
return "І" .. post
end
end
)
if modstem == stem then
error("Indicator 'io' can't be undone because stem '" .. stem .. "' doesn't have о as its last vowel")
end
return modstem
elseif base.ialt == "ijo" then
local modstem = rsub(stem, "ьо(́?" .. com.cons_c .. "*)$", "і%1")
if modstem == stem then
error("Indicator 'ijo' can't be undone because stem '" .. stem .. "' doesn't have ьо as its last vowel")
end
return modstem
elseif base.ialt == "ie" then
local modstem = rsub(stem, "([еЕєЄ])(́?" .. com.cons_c .. "*)$",
function(vowel, post)
local reverse_vowel = {
["е"] = "і",
["Е"] = "І",
["є"] = "ї",
["Є"] = "Ї",
}
return reverse_vowel[vowel] .. post
end
)
if modstem == stem then
error("Indicator 'ie' can't be undone because stem '" .. stem .. "' doesn't have е or є as its last vowel")
end
return modstem
elseif base.ialt == "i" then
error("Don't currently know how to undo 'i' vowel alternation")
else
return stem
end
end
-- For a plural-only lemma, synthesize a likely singular lemma. It doesn't have to be
-- theoretically correct as long as it generates all the correct plural forms (which mostly
-- means the nominative and genitive plural as the remainder are either derived or the same
-- for all declensions, modulo soft vs. hard).
local function synthesize_singular_lemma(base)
local stem, ac
while true do
-- Check neuter endings.
if base.neutertype == "t" then
stem, ac = rmatch(base.lemma, "^(.*[яа])(́)та$")
if stem then
base.lemma = stem .. ac
break
end
error("Unrecognized lemma for 't' indicator: '" .. base.lemma .. "'")
end
stem, ac = rmatch(base.lemma, "^(.*" .. com.hushing_c .. ")а(́?)$")
if stem then
base.lemma = stem .. "е" .. ac
break
end
stem, ac = rmatch(base.lemma, "^(.*)а(́?)$")
if stem then
base.lemma = stem .. "о" .. ac
break
end
stem, ac = rmatch(base.lemma, "^(.*)я(́?)$")
if stem then
-- Conceivably it should have the -я ending in the singular but I don't
-- think it matters.
base.lemma = stem .. "е" .. ac
break
end
-- Handle masculine/feminine endings.
stem, ac = rmatch(base.lemma, "^(.*)и(́?)$")
if stem then
if not base.gender then
error("For plural-only lemma in -и, need to specify the gender: '" .. base.lemma .. "'")
end
if base.gender == "M" then
base.lemma = undo_vowel_alternation(base, stem)
else
base.lemma = stem .. "а" .. ac
end
break
end
local vowel
stem, vowel, ac = rmatch(base.lemma, "^(.*)([ії])(́?)$")
if stem then
if not base.gender then
error("For plural-only lemma in -" .. vowel .. ", need to specify the gender: '" .. base.lemma .. "'")
end
if base.gender == "M" then
if rfind(stem, "[дтсзлнц]$") then
base.lemma = stem .. "ь"
elseif rfind(stem, "р$") then
base.lemma = stem
if not base.rtype then
-- add an override to cause the -і/-ї to appear
table.insert(base.overrides, {values = {{form = vowel}}})
end
elseif vowel == "ї" then
base.lemma = stem .. "й"
else
base.lemma = stem
end
base.lemma = undo_vowel_alternation(base, base.lemma)
elseif base.gender == "F" or base.gender == "MF" then
if base.thirddecl then
if rfind(stem, "[дтсзлнц]$") then
base.lemma = stem .. "ь"
else
base.lemma = stem
end
base.lemma = undo_vowel_alternation(base, base.lemma)
elseif rfind(stem, com.hushing_c .. "$") then
base.lemma = stem .. "а" .. ac
else
base.lemma = stem .. "я" .. ac
end
else
error("Don't know how to handle neuter plural-only nouns in -" .. vowel .. ": '" .. base.lemma .. "'")
end
break
end
error("Don't recognize ending of lemma '" .. base.lemma .. "'")
end
-- Now set the stress pattern if not given.
if not base.stresses then
base.stresses = {{reducible = false, genpl_reversed = false}}
end
for _, stress in ipairs(base.stresses) do
if not stress.stress then
if ac == AC then
stress.stress = "b"
else
stress.stress = "a"
end
end
end
end
-- For an adjectival lemma, synthesize the masc singular form.
local function synthesize_adj_lemma(base)
local stem, ac
local gender, number
while true do
-- Masculine
stem, ac = rmatch(base.lemma, "^(.*)[иії](́?)й$")
if stem then
gender = "M"
break
end
stem, ac = rmatch(base.lemma, "^(.*[оеєії]́?в)$")
if stem then
gender = "M"
break
end
stem, ac = rmatch(base.lemma, "^(.*[иії]́?н)$")
if stem then
gender = "M"
break
end
-- Feminine
stem, ac = rmatch(base.lemma, "^(.*)а(́?)$")
if stem then
base.lemma = stem .. "и" .. ac .. "й"
gender = "F"
break
end
stem, ac = rmatch(base.lemma, "^(.*ц)я(́?)$")
if stem then
base.lemma = stem .. "и" .. ac .. "й"
gender = "F"
break
end
stem, ac = rmatch(base.lemma, "^(.*" .. com.vowel .. AC .. "?)я(́?)$")
if stem then
base.lemma = stem .. "ї" .. ac .. "й"
gender = "F"
break
end
stem, ac = rmatch(base.lemma, "^(.*)я(́?)$")
if stem then
base.lemma = stem .. "і" .. ac .. "й"
gender = "F"
break
end
-- Neuter
stem, ac = rmatch(base.lemma, "^(.*)е(́?)$")
if stem then
base.lemma = stem .. "и" .. ac .. "й"
gender = "N"
break
end
stem, ac = rmatch(base.lemma, "^(.*ц)е(́?)$")
if stem then
base.lemma = stem .. "и" .. ac .. "й"
gender = "N"
break
end
stem, ac = rmatch(base.lemma, "^(.*" .. com.vowel .. AC .. "?)є(́?)$")
if stem then
base.lemma = stem .. "ї" .. ac .. "й"
gender = "N"
break
end
stem, ac = rmatch(base.lemma, "^(.*)є(́?)$")
if stem then
base.lemma = stem .. "і" .. ac .. "й"
gender = "N"
break
end
-- Plural
stem, ac = rmatch(base.lemma, "^(.*ц)і(́?)$")
if stem then
base.lemma = stem .. "и" .. ac .. "й"
number = "pl"
break
end
stem, ac = rmatch(base.lemma, "^(.*" .. com.vowel .. AC .. "?)ї(́?)$")
if stem then
base.lemma = stem .. "ї" .. ac .. "й"
number = "pl"
break
end
stem, ac = rmatch(base.lemma, "^(.*)і(́?)$")
if stem then
if base.soft then
base.lemma = stem .. "і" .. ac .. "й"
else
base.lemma = stem .. "и" .. ac .. "й"
end
number = "pl"
break
end
error("Don't recognize ending of adjectival lemma '" .. base.lemma .. "'")
end
if gender then
if base.gender and base.gender ~= gender then
error("Explicit gender '" .. base.gender .. "' disagrees with detected gender '" .. gender .. "'")
end
base.gender = gender
end
if number then
if base.number and base.number ~= number then
error("Explicit number '" .. base.number .. "' disagrees with detected number '" .. number .. "'")
end
base.number = number
end
-- Now set the stress pattern if not given.
if not base.stresses then
base.stresses = {{reducible = false, genpl_reversed = false}}
end
for _, stress in ipairs(base.stresses) do
if not stress.stress then
if ac == AC then
stress.stress = "b"
else
stress.stress = "a"
end
end
-- Set the stems.
stress.vowel_stem = stem
stress.nonvowel_stem = stem
stress.pl_vowel_stem = stem
stress.pl_nonvowel_stem = stem
end
base.decl = "adj"
end
local function check_indicators_match_lemma(base)
-- Check for indicators that don't make sense given the context.
if base.rtype and not rfind(base.lemma, "р$") then
error("'р' type indicator '" .. base.rtype .. "' can only be specified with a lemma ending in -р")
end
if base.remove_in and not rfind(base.lemma, "и́?н$") then
error("'in' can only be specified with a lemma ending in -ин")
end
if base.neutertype then
if not rfind(base.lemma, "я́?$") and not rfind(base.lemma, com.hushing_c .. "а́?$") then
error("Neuter-type indicator '" .. base.neutertype .. "' can only be specified with a lemma ending in -я or hushing consonant + -а")
end
if base.neutertype == "en" and not rfind(base.lemma, "м'я́?$") then
error("Neuter-type indicator 'en' can only be specified with a lemma ending in -м'я")
end
end
end
-- Determine the declension based on the lemma and whatever gender has been already given,
-- and set the gender to a default if not given. The declension is set in base.decl.
-- In the process, we set either base.vowel_stem (if the lemma ends in a vowel) or
-- base.nonvowel_stem (if the lemma does not end in a vowel), which is used by
-- determine_stress_and_stems().
local function determine_declension_and_gender(base)
-- Determine declension and set gender
local stem
stem = rmatch(base.lemma, "^(.*)ь$")
if stem then
if not base.gender then
if rfind(base.lemma, "[еє]́?ць$") then
base.gender = "M"
elseif rfind(base.lemma, "тель$") then
base.gender = "M"
elseif rfind(base.lemma, "[ії]сть$") then
base.gender = "F"
else
error("For lemma ending in -ь other than -ець/-єць/-тель/-ість/-їсть, gender M or F must be given")
end
end
if base.gender == "N" or base.gender == "MF" then
error("For lemma ending in -ь, gender " .. base.gender .. " not allowed")
elseif base.gender == "M" then
base.decl = "soft-m"
else
base.decl = "third-f"
end
base.nonvowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)й$")
if stem then
base.decl = "j-m"
if base.gender and base.gender ~= "M" then
error("For lemma ending in -й, gender " .. base.gender .. " not allowed")
end
base.gender = "M"
base.nonvowel_stem = stem
base.stem_for_reduce = base.lemma
return
end
stem = rmatch(base.lemma, "^(.*" .. com.hushing_c .. ")$")
if stem then
if base.gender == "N" or base.gender == "MF" then
error("For lemma ending in a hushing consonant, gender " .. base.gender .. " not allowed")
elseif base.gender == "F" then
base.decl = "third-f"
else
base.gender = "M"
base.decl = "semisoft-m"
end
base.nonvowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*" .. com.hushing_c .. ")а́?$")
if stem then
if base.neutertype == "t" then
base.decl = "t-n"
elseif base.gender == "N" then
error("For lemma ending in a hushing consonant + -а, gender N not allowed unless spec 't' is given")
else
base.decl = "semisoft-f"
base.gender = base.gender or "F"
end
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)а́?$")
if stem then
base.decl = "hard-f"
if base.gender == "N" then
error("For lemma ending in -а, gender N not allowed")
end
base.gender = base.gender or "F"
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)я́?$")
if stem then
if base.neutertype == "en" then
base.decl = "en-n"
elseif base.neutertype == "t" then
base.decl = "t-n"
elseif base.gender == "N" then
base.decl = "ja-n"
elseif not base.gender and (rfind(stem, "'$") or rfind(stem, "(.)%1$")) then
base.decl = "ja-n"
base.gender = "N"
elseif rfind(stem, com.vowel_c .. AC .. "?$") or rfind(stem, "['ьй]$") then
base.decl = "j-f"
base.gender = base.gender or "F"
else
base.decl = "soft-f"
base.gender = base.gender or "F"
end
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)о́?$")
if stem then
if base.gender == "M" or base.gender == "F" or base.gender == "MF" then
if rfind(stem, "ь$") then
stem = rsub(stem, "ь$", "")
base.decl = "soft-o-m"
else
base.decl = "o-m"
end
else
base.decl = "hard-n"
base.gender = "N"
end
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*" .. com.hushing_c .. ")е́?$")
if stem then
if base.gender == "M" then
base.decl = "semisoft-e-m"
elseif base.gender == "F" then
base.decl = "semisoft-e-f"
else
base.decl = "semisoft-n"
if base.gender == "MF" then
error("For lemma ending in -е, gender " .. base.gender .. " not allowed")
end
base.gender = base.gender or "N"
end
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)е́?$")
if stem then
base.decl = "soft-n"
if base.gender == "F" or base.gender == "MF" then
error("For lemma ending in -е, gender " .. base.gender .. " not allowed")
end
base.gender = base.gender or "N"
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*)є́?$")
if stem then
base.decl = "j-n"
if base.gender == "F" or base.gender == "MF" then
error("For lemma ending in -є, gender " .. base.gender .. " not allowed")
end
base.gender = base.gender or "N"
base.vowel_stem = stem
return
end
stem = rmatch(base.lemma, "^(.*" .. com.cons_c .. ")$")
if stem then
if base.gender == "N" or base.gender == "MF" then
error("For lemma ending in a consonant, gender " .. base.gender .. " not allowed")
elseif base.gender == "F" then
base.decl = "third-f"
elseif base.rtype == "soft" then
base.decl = "soft-m"
elseif base.rtype == "semisoft" then
base.decl = "semisoft-m"
else
base.decl = "hard-m"
end
base.gender = base.gender or "M"
base.nonvowel_stem = stem
return
end
error("Unrecognized ending for lemma: '" .. base.lemma .. "'")
end
-- Determine the stress pattern(s) if not explicitly given, as well as the stems
-- to use for each specified stress pattern: vowel and nonvowel stems, for singular
-- and plural. We assume that one of base.vowel_stem or base.nonvowel_stem has been
-- set in determine_declension_and_gender(), depending on whether the lemma ends in
-- a vowel. We construct all the rest given the stress pattern, reducibility, and
-- any explicit stems given. We store the determined stems inside of the stress objects
-- in `base.stresses`, meaning that if the user gave multiple stress patterns, we
-- will compute multiple sets of stems. The reason is that the stems may vary depending
-- on the stress pattern and reducibility. The dependency on reducibility should be
-- obvious but there is also dependency on the stress pattern in that in stress patterns
-- d, d', f and f' the lemma is given in end-stressed form but some other forms need to
-- be stem-stressed. We make the stems stressed on the last syllable for pattern d
-- (множина́ pl. множи́ни) but but on the first syllable for the remaining patterns
-- (голова́ pl. го́лови, сковорода́ pl. ско́вороди, both pattern d').
local function determine_stress_and_stems(base)
if not base.stresses then
base.stresses = {{reducible = false, genpl_reversed = false}}
end
if base.stem then
base.stem = com.add_monosyllabic_stress(base.stem)
end
if base.plstem then
base.plstem = com.add_monosyllabic_stress(base.plstem)
end
local end_stressed_lemma = rfind(base.lemma, AC .. "$")
for _, stress in ipairs(base.stresses) do
local function dereduce(stem)
local epenthetic_stress = stress_patterns[stress.stress].gen_p == "+"
if stress.genpl_reversed then
epenthetic_stress = not epenthetic_stress
end
local dereduced_stem = com.dereduce(stem, epenthetic_stress)
if not dereduced_stem then
error("Unable to dereduce stem '" .. stem .. "'")
end
return dereduced_stem
end
if not stress.stress then
if base.gender ~= "N" and rfind(base.lemma, "[ое]́$") then
-- masculine or feminine in -о or -е
stress.stress = "b"
elseif stress.reducible and rfind(base.lemma, "[еоєі]́" .. com.cons_c .. "ь?$") then
-- reducible with stress on the reducible vowel
stress.stress = "b"
elseif rfind(base.lemma, "[ая]́$") and base.gender == "N" then
stress.stress = "b"
elseif end_stressed_lemma then
stress.stress = "d"
else
stress.stress = "a"
end
end
if stress.stress ~= "b" then
if base.stem and com.needs_accents(base.stem) then
error("Explicit stem needs an accent with stress pattern " .. stress.stress .. ": '" .. base.stem .. "'")
end
if base.plstem and com.needs_accents(base.plstem) then
error("Explicit plural stem needs an accent with stress pattern " .. stress.stress .. ": '" .. base.plstem .. "'")
end
end
local lemma_is_vowel_stem = not not base.vowel_stem
if base.vowel_stem then
if end_stressed_lemma and stress_patterns[stress.stress].nom_s ~= "+" then
error("Stress pattern " .. stress.stress .. " requires a stem-stressed lemma, not end-stressed: '" .. base.lemma .. "'")
elseif not end_stressed_lemma and stress_patterns[stress.stress].nom_s == "+" then
error("Stress pattern " .. stress.stress .. " requires an end-stressed lemma, not stem-stressed: '" .. base.lemma .. "'")
end
if base.stem then
error("Can't specify 'stem:' with lemma ending in a vowel")
end
stress.vowel_stem = add_stress_for_pattern(stress, base.vowel_stem)
if base.gender == "N" and rfind(base.lemma, "(.)%1я́?$") then
-- значе́ння -> gen pl значе́нь
stress.nonvowel_stem = rsub(stress.vowel_stem, ".$", "")
else
stress.nonvowel_stem = stress.vowel_stem
end
-- Apply vowel alternation first in cases like війна́ -> во́єн;
-- apply_vowel_alternation() will throw an error if the vowel being
-- modified isn't the last vowel in the stem.
stress.nonvowel_stem, stress.origvowel = com.apply_vowel_alternation(base.ialt, stress.nonvowel_stem)
if stress.reducible then
stress.nonvowel_stem = dereduce(stress.nonvowel_stem)
end
else
stress.nonvowel_stem = add_stress_for_pattern(stress, base.nonvowel_stem)
if stress.reducible then
local stem_to_reduce = base.stem_for_reduce or base.nonvowel_stem
stress.vowel_stem = com.reduce(stem_to_reduce)
if not stress.vowel_stem then
error("Unable to reduce stem '" .. stem_to_reduce .. "'")
end
else
stress.vowel_stem = base.nonvowel_stem
end
if base.stem and base.stem ~= stress.vowel_stem then
stress.irregular_stem = true
stress.vowel_stem = base.stem
end
stress.vowel_stem, stress.origvowel = com.apply_vowel_alternation(base.ialt, stress.vowel_stem)
stress.vowel_stem = add_stress_for_pattern(stress, stress.vowel_stem)
end
if base.remove_in then
stress.pl_vowel_stem = com.maybe_stress_final_syllable(rsub(stress.vowel_stem, "и́?н$", ""))
stress.pl_nonvowel_stem = stress.pl_vowel_stem
else
stress.pl_vowel_stem = stress.vowel_stem
stress.pl_nonvowel_stem = stress.nonvowel_stem
end
if base.plstem then
local stressed_plstem = add_stress_for_pattern(stress, base.plstem)
if stressed_plstem ~= stress.pl_vowel_stem then
stress.irregular_plstem = true
end
stress.pl_vowel_stem = stressed_plstem
if lemma_is_vowel_stem then
-- If the original lemma ends in a vowel (neuters and most feminines),
-- apply i/e/o vowel alternations and dereductions to the explicit plural
-- stem, because they most likely apply in the genitive plural. This is
-- needed for various words, e.g. ко́лесо (plstem коле́с-, gen pl колі́с,
-- alternative ins pl колі́сьми, both with е -> і alternation); гра
-- (plstem ігр-, gen pl і́гор, with dereduction); likewise ре́шето with
-- special plstem and е -> і alternation and скло with special plstem and
-- dereduction. But we don't want it in lemmas ending in a consonant,
-- where the vowel alternations and reductions apply between nom sg and
-- the remaining forms, not generally in the plural. For example, со́кіл
-- "falcon" has both і -> о alternation (vowel stem со́кол-) and special
-- plstem соко́л-, but we can't and don't want to apply an і -> о
-- alternation to the plstem.
stress.pl_nonvowel_stem = com.apply_vowel_alternation(base.ialt, stressed_plstem)
if stress.reducible then
stress.pl_nonvowel_stem = dereduce(stress.pl_nonvowel_stem)
end
else
stress.pl_nonvowel_stem = stressed_plstem
end
end
end
end
local function detect_indicator_spec(base)
set_defaults_and_check_bad_indicators(base)
if base.adj then
process_declnumber(base)
synthesize_adj_lemma(base)
else
if base.number == "pl" then
synthesize_singular_lemma(base)
end
check_indicators_match_lemma(base)
determine_declension_and_gender(base)
determine_stress_and_stems(base)
end
end
local function detect_all_indicator_specs(alternant_multiword_spec)
local is_multiword = #alternant_multiword_spec.alternant_or_word_specs > 1
iut.map_word_specs(alternant_multiword_spec, function(base)
detect_indicator_spec(base)
base.multiword = is_multiword
end)
end
local propagate_multiword_properties
local function propagate_alternant_properties(alternant_spec, property, mixed_value, nouns_only)
local seen_property
for _, multiword_spec in ipairs(alternant_spec.alternants) do
propagate_multiword_properties(multiword_spec, property, mixed_value, nouns_only)
if seen_property == nil then
seen_property = multiword_spec[property]
elseif multiword_spec[property] and seen_property ~= multiword_spec[property] then
seen_property = mixed_value
end
end
alternant_spec[property] = seen_property
end
propagate_multiword_properties = function(multiword_spec, property, mixed_value, nouns_only)
local seen_property = nil
local last_seen_nounal_pos = 0
local word_specs = multiword_spec.alternant_or_word_specs or multiword_spec.word_specs
for i = 1, #word_specs do
local is_nounal
if word_specs[i].alternants then
propagate_alternant_properties(word_specs[i], property, mixed_value)
is_nounal = not not word_specs[i][property]
elseif nouns_only then
is_nounal = not word_specs[i].adj
else
is_nounal = not not word_specs[i][property]
end
if is_nounal then
if word_specs[i][property] == nil then
error("Internal error: noun-type word spec without " .. property .. " set")
end
for j = last_seen_nounal_pos + 1, i - 1 do
word_specs[j][property] = word_specs[j][property] or word_specs[i][property]
end
last_seen_nounal_pos = i
if seen_property == nil then
seen_property = word_specs[i][property]
elseif seen_property ~= word_specs[i][property] then
seen_property = mixed_value
end
end
end
if last_seen_nounal_pos > 0 then
for i = last_seen_nounal_pos + 1, #word_specs do
word_specs[i][property] = word_specs[i][property] or word_specs[last_seen_nounal_pos][property]
end
end
multiword_spec[property] = seen_property
end
local function propagate_properties_downward(alternant_multiword_spec, property, default_propval)
local function set_and_fetch(obj, default)
if obj[property] then
return obj[property]
else
obj[property] = default
return default
end
end
local propval1 = set_and_fetch(alternant_multiword_spec, default_propval)
for _, alternant_or_word_spec in ipairs(alternant_multiword_spec.alternant_or_word_specs) do
local propval2 = set_and_fetch(alternant_or_word_spec, propval1)
if alternant_or_word_spec.alternants then
for _, multiword_spec in ipairs(alternant_or_word_spec.alternants) do
local propval3 = set_and_fetch(multiword_spec, propval2)
for _, word_spec in ipairs(multiword_spec.word_specs) do
local propval4 = set_and_fetch(word_spec, propval3)
if propval4 == "mixed" then
error("Attempt to assign mixed " .. property .. " to word")
end
word_spec[property] = propval4
end
end
else
if propval2 == "mixed" then
error("Attempt to assign mixed " .. property .. " to word")
end
alternant_or_word_spec[property] = propval2
end
end
end
--[=[
Propagate `property` (one of "animacy", "gender" or "number") from nouns to adjacent
adjectives. We proceed as follows:
1. We assume the properties in question are already set on all nouns. This should happen
in set_defaults_and_check_bad_indicators().
2. We first propagate properties upwards and sideways. We recurse downwards from the top.
When we encounter a multiword spec, we proceed left to right looking for a noun.
When we find a noun, we fetch its property (recursing if the noun is an alternant),
and propagate it to any adjectives to its left, up to the next noun to the left.
When we have processed the last noun, we also propagate its property value to any
adjectives to the right (to handle e.g. [[лунь польовий]] "hen harrier", where the
adjective польовий should inherit the 'animal' animacy of лунь). Finally, we set
the property value for the multiword spec itself by combining all the non-nil
properties of the individual elements. If all non-nil properties have the same value,
the result is that value, otherwise it is `mixed_value` (which is "mixed" for animacy
and gender, but "both" for number).
3. When we encounter an alternant spec in this process, we recursively process each
alternant (which is a multiword spec) using the previous step, and combine any
non-nil properties we encounter the same way as for multiword specs.
4. The effect of steps 2 and 3 is to set the property of each alternant and multiword
spec based on its children or its neighbors.
]=]
local function propagate_properties(alternant_multiword_spec, property, default_propval, mixed_value)
propagate_multiword_properties(alternant_multiword_spec, property, mixed_value, "nouns only")
propagate_multiword_properties(alternant_multiword_spec, property, mixed_value, false)
propagate_properties_downward(alternant_multiword_spec, property, default_propval)
end
local function determine_noun_status(alternant_multiword_spec)
for i, alternant_or_word_spec in ipairs(alternant_multiword_spec.alternant_or_word_specs) do
if alternant_or_word_spec.alternants then
local is_noun = false
for _, multiword_spec in ipairs(alternant_or_word_spec.alternants) do
for j, word_spec in ipairs(multiword_spec.word_specs) do
if not word_spec.adj then
multiword_spec.first_noun = j
is_noun = true
break
end
end
end
if is_noun then
alternant_multiword_spec.first_noun = i
end
elseif not alternant_or_word_spec.adj then
alternant_multiword_spec.first_noun = i
return
end
end
end
-- Check that multisyllabic lemmas have stress, and add stress to monosyllabic
-- lemmas if needed.
local function normalize_all_lemmas(alternant_multiword_spec)
iut.map_word_specs(alternant_multiword_spec, function(base)
base.orig_lemma = base.lemma
base.orig_lemma_no_links = com.add_monosyllabic_stress(m_links.remove_links(base.lemma))
base.lemma = base.orig_lemma_no_links
if not rfind(base.lemma, AC) then
error("Multisyllabic lemma '" .. base.orig_lemma .. "' needs an accent")
end
end)
end
local function decline_noun(base)
for _, stress in ipairs(base.stresses) do
if not decls[base.decl] then
error("Internal error: Unrecognized declension type '" .. base.decl .. "'")
end
decls[base.decl](base, stress)
end
handle_derived_slots_and_overrides(base)
local function copy(from_slot, to_slot)
base.forms[to_slot] = base.forms[from_slot]
end
if base.actual_number ~= base.number then
local source_num = base.number ~= "pl" and "_s" or "_p"
local dest_num = base.number == "sg" and "_p" or "_s"
for case, _ in pairs(cases) do
copy(case .. source_num, case .. dest_num)
copy("nom" .. source_num .. "_linked", "nom" .. dest_num .. "_linked")
end
if base.actual_number ~= "both" then
local erase_num = base.actual_number == "sg" and "_p" or "_s"
for case, _ in pairs(cases) do
base.forms[case .. erase_num] = nil
end
base.forms["nom" .. erase_num .. "_linked"] = nil
end
end
end
local function get_variants(form)
return
form:find(com.VAR1) and "var1" or
form:find(com.VAR2) and "var2" or
form:find(com.VAR3) and "var3" or
nil
end
local function process_manual_overrides(forms, args, number, unknown_stress)
local params_to_slots_map =
number == "sg" and input_params_to_slots_sg or
number == "pl" and input_params_to_slots_pl or
input_params_to_slots_both
for param, slot in pairs(params_to_slots_map) do
if args[param] then
forms[slot] = nil
if args[param] ~= "-" and args[param] ~= "—" then
for _, form in ipairs(rsplit(args[param], "%s*,%s*")) do
if com.is_multi_stressed(form) then
error("Multi-stressed form '" .. form .. "' in slot '" .. slot .. "' not allowed; use singly-stressed forms separated by commas")
end
if not unknown_stress and not rfind(form, "^%-") and com.needs_accents(form) then
error("Stress required in multisyllabic form '" .. form .. "' in slot '" .. slot .. "'; if stress is truly unknown, use unknown_stress=1")
end
iut.insert_form(forms, slot, {form=form})
end
end
end
end
end
-- Compute the categories to add the noun to, as well as the annotation to display in the
-- declension title bar. We combine the code to do these functions as both categories and
-- title bar contain similar information.
local function compute_categories_and_annotation(alternant_multiword_spec)
local cats = {}
local function insert(cattype)
-- m_table.insertIfNot(cats, "Ukrainian " .. cattype)
end
if alternant_multiword_spec.pos == "noun" then
if alternant_multiword_spec.actual_number == "sg" then
-- insert("uncountable nouns")
elseif alternant_multiword_spec.actual_number == "pl" then
-- insert("pluralia tantum")
end
end
local annotation
if alternant_multiword_spec.manual then
alternant_multiword_spec.annotation =
alternant_multiword_spec.actual_number == "sg" and "sg-only" or
alternant_multiword_spec.actual_number == "pl" and "pl-only" or
""
else
local annparts = {}
local animacies = {}
local decldescs = {}
local patterns = {}
local vowelalts = {}
local irregs = {}
local stems = {}
local reducible = nil
local function do_word_spec(base)
if base.animacy == "inan" then
m_table.insertIfNot(animacies, "inan")
elseif base.animacy == "anml" then
m_table.insertIfNot(animacies, "animal")
else
assert(base.animacy == "pr")
m_table.insertIfNot(animacies, "pers")
end
for _, stress in ipairs(base.stresses) do
local props = declprops[base.decl]
local desc = props.desc
if type(desc) == "function" then
desc = desc(base, stress)
end
m_table.insertIfNot(decldescs, desc)
local cats = props.cat
if type(cats) == "function" then
cats = cats(base, stress)
end
if type(cats) == "string" then
cats = {cats .. " nouns", cats .. " ~ nouns"}
end
for _, cat in ipairs(cats) do
cat = rsub(cat, "~", "accent-" .. stress.stress)
insert(cat)
end
m_table.insertIfNot(patterns, stress.stress)
-- insert("nouns with accent pattern " .. stress.stress)
local vowelalt
if base.ialt == "ie" then
vowelalt = "і-е"
elseif base.ialt == "io" then
vowelalt = "і-о"
elseif base.ialt == "ijo" then
vowelalt = "і-ьо"
elseif base.ialt == "i" then
if not stress.origvowel then
error("Internal error: Original vowel not set along with 'i' code")
end
vowelalt = ulower(stress.origvowel) .. "-і"
end
if vowelalt then
m_table.insertIfNot(vowelalts, vowelalt)
-- insert("nouns with " .. vowelalt .. " alternation")
end
if reducible == nil then
reducible = stress.reducible
elseif reducible ~= stress.reducible then
reducible = "mixed"
end
if stress.reducible then
-- insert("nouns with reducible stem")
end
if stress.irregular_stem then
m_table.insertIfNot(irregs, "irreg-stem")
-- insert("nouns with irregular stem")
end
if stress.irregular_plstem then
m_table.insertIfNot(irregs, "irreg-plstem")
-- insert("nouns with irregular plural stem")
end
m_table.insertIfNot(stems, stress.vowel_stem)
end
end
local key_entry = alternant_multiword_spec.first_noun or 1
if #alternant_multiword_spec.alternant_or_word_specs >= key_entry then
local alternant_or_word_spec = alternant_multiword_spec.alternant_or_word_specs[key_entry]
if alternant_or_word_spec.alternants then
for _, multiword_spec in ipairs(alternant_or_word_spec.alternants) do
key_entry = multiword_spec.first_noun or 1
if #multiword_spec.word_specs >= key_entry then
do_word_spec(multiword_spec.word_specs[key_entry])
end
end
else
do_word_spec(alternant_or_word_spec)
end
end
if #animacies > 0 then
table.insert(annparts, table.concat(animacies, "/"))
end
if alternant_multiword_spec.actual_number ~= "both" then
table.insert(annparts, alternant_multiword_spec.actual_number == "sg" and "sg-only" or "pl-only")
end
if #decldescs == 0 then
table.insert(annparts, "indecl")
else
table.insert(annparts, table.concat(decldescs, " // "))
end
if #patterns > 0 then
table.insert(annparts, "accent-" .. table.concat(patterns, "/"))
end
if #vowelalts > 0 then
table.insert(annparts, table.concat(vowelalts, "/"))
end
if reducible == "mixed" then
table.insert(annparts, "mixed-reduc")
elseif reducible then
table.insert(annparts, "reduc")
end
if #irregs > 0 then
table.insert(annparts, table.concat(irregs, " // "))
end
alternant_multiword_spec.annotation = table.concat(annparts, " ")
if #patterns > 1 then
-- insert("nouns with multiple accent patterns")
end
if #stems > 1 then
-- insert("nouns with multiple stems")
end
end
alternant_multiword_spec.categories = cats
end
local function show_forms(alternant_multiword_spec)
local lemmas = {}
if alternant_multiword_spec.forms.nom_s then
for _, nom_s in ipairs(alternant_multiword_spec.forms.nom_s) do
table.insert(lemmas, com.remove_monosyllabic_stress(nom_s.form))
end
elseif alternant_multiword_spec.forms.nom_p then
for _, nom_p in ipairs(alternant_multiword_spec.forms.nom_p) do
table.insert(lemmas, com.remove_monosyllabic_stress(nom_p.form))
end
end
local props = {
lemmas = lemmas,
slot_table = output_noun_slots_with_linked,
lang = lang,
canonicalize = function(form)
return com.remove_variant_codes(com.remove_monosyllabic_stress(form))
end,
include_translit = true,
-- Explicit additional top-level footnotes only occur with {{uk-ndecl-manual}} and variants.
footnotes = alternant_multiword_spec.footnotes,
allow_footnote_symbols = not not alternant_multiword_spec.footnotes,
}
iut.show_forms(alternant_multiword_spec.forms, props)
end
local function make_table(alternant_multiword_spec)
local forms = alternant_multiword_spec.forms
local table_spec_both = [=[
|- class="outer"
!
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
|-
! မဒုၚ်ယၟု
| data-accel-col=1 | {nom_s}
| data-accel-col=2 | {nom_p}
|-
! ဗဳဇဂကူ
| data-accel-col=1 | {gen_s}
| data-accel-col=2 | {gen_p}
|-
! ပြကမ္မကာရက
| data-accel-col=1 | {dat_s}
| data-accel-col=2 | {dat_p}
|-
! ကမ္မကာရက
| data-accel-col=1 | {acc_s}
| data-accel-col=2 | {acc_p}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_s}
| data-accel-col=2 | {ins_p}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| data-accel-col=1 | {loc_s}
| data-accel-col=2 | {loc_p}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| data-accel-col=1 | {voc_s}
| data-accel-col=2 | {voc_p}
]=]
local table_spec_sg = [=[
|- class="outer"
!
! ကိုန်ဨကဝုစ်
|-
! မဒုၚ်ယၟု
| data-accel-col=1 | {nom_s}
|-
! ဗဳဇဂကူ
| data-accel-col=1 | {gen_s}
|-
! ပြကမ္မကာရက
| data-accel-col=1 | {dat_s}
|-
! ကမ္မကာရက
| data-accel-col=1 | {acc_s}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=1 | {ins_s}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| data-accel-col=1 | {loc_s}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| data-accel-col=1 | {voc_s}
]=]
local table_spec_pl = [=[
|- class="outer"
!
! ကိုန်ဗဟုဝစ်
|-
! မဒုၚ်ယၟု
| data-accel-col=2 | {nom_p}
|-
! ဗဳဇဂကူ
| data-accel-col=2 | {gen_p}
|-
! ပြကမ္မကာရက
| data-accel-col=2 | {dat_p}
|-
! ကမ္မကာရက
| data-accel-col=2 | {acc_p}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| data-accel-col=2 | {ins_p}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| data-accel-col=2 | {loc_p}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| data-accel-col=2 | {voc_p}
]=]
if alternant_multiword_spec.title then
forms.title = alternant_multiword_spec.title
else
forms.title = 'မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု <i lang="uk" class="Cyrl">' .. forms.lemma .. '</i>'
end
local annotation = alternant_multiword_spec.annotation
if annotation == "" then
forms.annotation = ""
else
forms.annotation = " (<span style=\"font-size: smaller;\">" .. annotation .. "</span>)"
end
local frame = mw.getCurrentFrame()
local table_spec = alternant_multiword_spec.actual_number == "sg" and table_spec_sg or
alternant_multiword_spec.actual_number == "pl" and table_spec_pl or
table_spec_both
local full_table_spec = frame:expandTemplate{
title = 'inflection-table-top',
args = {
lang = "uk",
title = "{title}<br>{annotation}",
palette = "blue",
tall = "yes",
class = "sticky-left-column tr-alongside"
}
} .. table_spec .. frame:expandTemplate{
title = "inflection-table-bottom",
args = {
notes = "{footnote}",
}
}
return m_string_utilities.format(full_table_spec, forms)
end
local function compute_headword_genders(alternant_multiword_spec)
local genders = {}
local number
if alternant_multiword_spec.actual_number == "pl" then
number = "-p"
else
number = ""
end
iut.map_word_specs(alternant_multiword_spec, function(base)
local animacy = base.animacy
if animacy == "inan" then
animacy = "in"
end
if base.gender == "MF" then
m_table.insertIfNot(genders, "m-" .. animacy .. number)
m_table.insertIfNot(genders, "f-" .. animacy .. number)
elseif base.gender == "M" then
m_table.insertIfNot(genders, "m-" .. animacy .. number)
elseif base.gender == "F" then
m_table.insertIfNot(genders, "f-" .. animacy .. number)
elseif base.gender == "N" then
m_table.insertIfNot(genders, "n-" .. animacy .. number)
else
error("Internal error: Unrecognized gender '" ..
(base.gender or "nil") .. "'")
end
end)
return genders
end
--[==[
Externally callable function to parse and decline a noun given user-specified arguments.
Return value is ```alternant_multiword_spec```, an object where the declined forms are in
```alternant_multiword_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(args, pos, from_headword, def)
local parse_props = {
parse_indicator_spec = parse_indicator_spec,
}
local alternant_multiword_spec = iut.parse_inflected_text(args[1], parse_props)
alternant_multiword_spec.title = args.title
alternant_multiword_spec.pos = args.pos or pos
alternant_multiword_spec.footnotes = args.footnote
alternant_multiword_spec.args = args
normalize_all_lemmas(alternant_multiword_spec)
detect_all_indicator_specs(alternant_multiword_spec)
propagate_properties(alternant_multiword_spec, "animacy", "inan", "mixed")
propagate_properties(alternant_multiword_spec, "number", "both", "both")
-- The default of "M" should apply only to plural adjectives, where it doesn't matter.
propagate_properties(alternant_multiword_spec, "gender", "M", "mixed")
propagate_properties(alternant_multiword_spec, "actual_number", "both", "both")
propagate_properties(alternant_multiword_spec, "usuallysg", false, true)
determine_noun_status(alternant_multiword_spec)
local inflect_props = {
skip_slot = function(slot)
return skip_slot(alternant_multiword_spec.actual_number, slot)
end,
slot_table = output_noun_slots_with_linked,
get_variants = get_variants,
inflect_word_spec = decline_noun,
}
iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props)
compute_categories_and_annotation(alternant_multiword_spec)
alternant_multiword_spec.genders = compute_headword_genders(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 a noun where all forms are given manually.
Return value is ```alternant_multiword_spec```, an object where the declined forms are in
```alternant_multiword_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(args, number, pos, from_headword, def)
local alternant_multiword_spec = {
title = args.title,
footnotes = args.footnote,
pos = args.pos or pos,
forms = {},
number = number,
actual_number = number,
manual = true,
}
process_manual_overrides(alternant_multiword_spec.forms, args, alternant_multiword_spec.actual_number,
args.unknown_stress)
compute_categories_and_annotation(alternant_multiword_spec)
return alternant_multiword_spec
end
--[==[
Entry point for {{tl|uk-ndecl}}. Template-callable function to parse and decline a noun given
user-specified arguments and generate a displayable table of the declined forms.
]==]
function export.show(frame)
local parent_args = frame:getParent().args
local params = {
[1] = {required = true, template_default = "віз<c.io>"},
footnote = {list = true},
title = true,
pos = {default = "noun"},
json = {type = "boolean"}, -- for bot use
}
local args = m_para.process(parent_args, params)
local alternant_multiword_spec = export.do_generate_forms(args)
if type(alternant_multiword_spec) == "string" then
-- JSON return value
return alternant_multiword_spec
end
show_forms(alternant_multiword_spec)
return make_table(alternant_multiword_spec) ..
require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang, nil, nil, force_cat)
end
--[==[
Entry point for {{tl|uk-ndecl-manual}}, {{tl|uk-ndecl-manual-sg}} and {{tl|uk-ndecl-manual-pl}}.
Template-callable function to parse and decline a noun given manually-specified inflections
and generate a displayable table of the declined forms.
]==]
function export.show_manual(frame)
local iparams = {
[1] = {required = true},
}
local iargs = m_para.process(frame.args, iparams)
local parent_args = frame:getParent().args
local params = {
footnote = {list = true},
title = true,
unknown_stress = {type = "boolean"},
pos = {default = "noun"},
}
local number = iargs[1]
if number ~= "sg" and number ~= "pl" and number ~= "both" then
error("Internal error: number (arg 1) must be 'sg', 'pl' or 'both': '" .. number .. "'")
end
if number == "both" then
params[1] = {required = true, template_default = "жук"}
params[2] = {required = true, template_default = "жуки́"}
params[3] = {required = true, template_default = "жука́"}
params[4] = {required = true, template_default = "жукі́в"}
params[5] = {required = true, template_default = "жуко́ві, жуку́"}
params[6] = {required = true, template_default = "жука́м"}
params[7] = {required = true, template_default = "жука́"}
params[8] = {required = true, template_default = "жуки́, жукі́в"}
params[9] = {required = true, template_default = "жуко́м"}
params[10] = {required = true, template_default = "жука́ми"}
params[11] = {required = true, template_default = "жуко́ві, жуку́"}
params[12] = {required = true, template_default = "жука́х"}
params[13] = {required = true, template_default = "жу́че"}
params[14] = {required = true, template_default = "жуки́"}
elseif number == "sg" then
params[1] = {required = true, template_default = "лист"}
params[2] = {required = true, template_default = "ли́сту"}
params[3] = {required = true, template_default = "ли́сту, ли́стові"}
params[4] = {required = true, template_default = "лист"}
params[5] = {required = true, template_default = "ли́стом"}
params[6] = {required = true, template_default = "ли́сті, ли́сту"}
params[7] = {required = true, template_default = "ли́сте"}
else
params[1] = {required = true, template_default = "две́рі"}
params[2] = {required = true, template_default = "двере́й"}
params[3] = {required = true, template_default = "две́рям"}
params[4] = {required = true, template_default = "две́рі"}
params[5] = {required = true, template_default = "дверми́, двери́ма"}
params[6] = {required = true, template_default = "две́рях"}
params[7] = {required = true, template_default = "две́рі"}
end
local args = m_para.process(parent_args, params)
local alternant_multiword_spec = export.do_generate_forms_manual(args, number)
show_forms(alternant_multiword_spec)
return make_table(alternant_multiword_spec) ..
require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang, nil, nil, force_cat)
end
return export
3iq8l20gchjagndv140ilwcveuolwk1
ထာမ်ပလိက်:hrow/styles.css
10
44725
399838
59119
2026-07-21T10:06:48Z
咽頭べさ
33
399838
sanitized-css
text/css
.ac-hrown+* {display: inline-grid; column-gap: 32px; grid-auto-flow: column;}
.ac-hrown+ol, .ac-hrown+ul {background: var(--wikt-palette-lavender,#F8F8FF); margin-left: 0; padding-left: 24px; padding-right: 24px;}
.ac-hrown.ct-width0 + * {grid-auto-columns: auto;}
.ac-hrown.ct-width1 + * {grid-auto-columns: 1fr;}
.ac-hrow1 + * {grid-template-rows: repeat(1, auto);}
.ac-hrow2 + * {grid-template-rows: repeat(2, auto);}
.ac-hrow3 + * {grid-template-rows: repeat(3, auto);}
.ac-hrow4 + * {grid-template-rows: repeat(4, auto);}
.ac-hrow5 + * {grid-template-rows: repeat(5, auto);}
.ac-hrow6 + * {grid-template-rows: repeat(6, auto);}
@media only screen and (max-width: 640px) {
.ac-hrown+* {grid-auto-flow: row;}
.ac-hrown+ol, .ac-hrown+ul {background: initial;}
}
7vfv5dhl5aqexs4ytyabvuovb5x9kgy
ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ရုဿျှာဂမၠိုၚ်
14
55593
399850
165936
2026-07-21T12:45:48Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာလေန်မနွံကဵုပၟိက်ဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ရုဿျှာဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
162957
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာဂမၠိုၚ်]]
ruw3wxcregmoe6y7zd9f8jivol3kl61
ထာမ်ပလိက်:csb-noun
10
57518
399931
158629
2026-07-23T06:15:20Z
咽頭べさ
33
399931
wikitext
text/x-wiki
{{#invoke:zlw-lch-headword|show|နာမ်|lang=csb}}<!--
--><noinclude>{{documentation}}</noinclude>
k8h76se1393fwxb1hqin2m2kba6yh0d
ထာမ်ပလိက်:csb-noun/documentation
10
57519
399932
75049
2026-07-23T06:16:36Z
咽頭べさ
33
399932
wikitext
text/x-wiki
{{documentation subpage}}
This template is to be used in the headword lines for Kashubian common nouns. The parameters are exactly identical to those for {{tl|pl-noun}} (and other Lechitic noun templates). See the documentation of that template for more information.
{{hwcat}}
plm9qxt4lfvm71cenfir9pgvqwrt6k7
ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ကသှုဗဳယာန်ဂမၠိုၚ်
14
57520
399933
165521
2026-07-23T06:51:46Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်ကသှုဗဳယာန်လေန်မနွံကဵုပၟိက်ဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ကသှုဗဳယာန်ဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
162678
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ကသှုဗဳယာန်ဂမၠိုၚ်]]
rwh5fudam2x1k9yfn6o6jxe2u4yszek
ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ယူကရိန်ဂမၠိုၚ်
14
64177
399816
165916
2026-07-21T06:10:59Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်လေန်မနွံကဵုပၟိက်ဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ယူကရိန်ဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
162947
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်ဂမၠိုၚ်]]
9wfuumdbpqgc336i35to6qnhd6mc8dc
မဝ်ဂျူ:labels/data/lang/pl
828
110457
399920
396218
2026-07-23T05:47:03Z
咽頭べさ
33
399920
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 = ":en:Kraków",
regional_categories = {true, "Urban"},
display = "ခရာကိုတ်",
parent = "ခရာကိုတ်လ္ပာ်ပလိုတ်",
}
labels["Lublin"] = {
Wikipedia = true,
regional_categories = true,
regional_categories = {true, "Urban"},
display = "လူဗလေန်",
parent = "လူဗလေန်လ္ပာ်ပလိုတ်",
}
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)
p70ipngaow1panvlbye62l4vorbijh2
မဝ်ဂျူ:sla-common
828
219643
399831
300204
2026-07-21T08:26:19Z
咽頭べさ
33
399831
Scribunto
text/plain
local export = {}
local m_links = require("Module:links")
local m_table_tools = require("Module:table tools")
local lang = require("Module:languages").getByCode("sla-pro")
local u = mw.ustring.char
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local toNFD = mw.ustring.toNFD
local ulower = mw.ustring.lower
local uupper = mw.ustring.upper
local usub = mw.ustring.sub
local AC = u(0x0301) -- acute = ́
local GR = u(0x0300) -- grave = ̀
local CFLEX = u(0x0302) -- circumflex = ̂
local TILDE = u(0x0303) -- tilde = ̃
local BREVE = u(0x0306) -- breve = ̆
local INVBREVE = u(0x0311) -- inverse breve = ̑
local DOUBLEAC = u(0x030B) -- double acute = ̋
local DOUBLEGR = u(0x030F) -- double grave = ̏
local MACRON = u(0x0304) -- macron = ̄
local CARON = u(0x030C) -- caron = ̌
local OGONEK = u(0x0328) -- ogonek = ̨
local stressed_accents = AC .. GR .. INVBREVE .. DOUBLEGR .. DOUBLEAC .. TILDE
local stressed_accents_c = "[" .. stressed_accents .. "]"
local accents = stressed_accents .. MACRON
local accents_c = "[" .. accents .. "]"
local vowels = "aeiouyьъěęǫ"
local vowels_c = "[" .. vowels .. "]"
local non_vowels_c = "[^" .. vowels .. "]"
local short_vowels = "eoьъ"
local short_vowels_c = "[" .. short_vowels .. "]"
local long_vowels = "aiuyěęǫ"
local long_vowels_c = "[" .. long_vowels .. "]"
local cons_c = "[^" .. vowels .. accents .. "]"
local iotated_cons = "čďjľňřšťž"
local iotated_cons_c = "[" .. iotated_cons .. "]"
-- 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
function export.tag_form(form, tag)
if form ~= "" then
return "<" .. (tag or "span") .. " lang=\"sla-pro\" class=\"Unicode\">*" .. form .. "</" .. (tag or "span") .. ">"
else
return "—"
end
end
-- Make a link out of a form, or show a dash if empty.
function export.link_form(form, tag)
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
if type(form) == "table" then
if not form.notesym then
local retval = {}
for _, subform in ipairs(form) do
table.insert(retval, export.link_form(subform, tag))
end
return table.concat(retval, ", ")
else
return m_links.full_link({ lang = lang, term = "*" .. form[1] }) .. m_table_tools.superscript_notes(form.notesym)
end
elseif form ~= "" then
return m_links.full_link({ lang = lang, term = "*" .. form })
else
return "—"
end
end
local recomposer = {
["e" .. CARON] = "ě", -- Latin e and E
["E" .. CARON] = "Ě",
["e" .. OGONEK] = "ę", -- Latin e and E
["E" .. OGONEK] = "Ę",
["o" .. OGONEK] = "ǫ", -- Latin o and O
["O" .. OGONEK] = "Ǫ",
["c" .. CARON] = "č",
["C" .. CARON] = "Č",
["d" .. CARON] = "ď",
["D" .. CARON] = "Ď",
["l" .. CARON] = "ľ",
["L" .. CARON] = "Ľ",
["n" .. CARON] = "ň",
["N" .. CARON] = "Ň",
["r" .. CARON] = "ř",
["R" .. CARON] = "Ř",
["s" .. AC] = "ś",
["S" .. AC] = "Ś",
["s" .. CARON] = "š",
["S" .. CARON] = "Š",
["t" .. CARON] = "ť",
["T" .. CARON] = "Ť",
["z" .. CARON] = "ž",
["Z" .. CARON] = "Ž",
}
-- Decompose acute, grave, etc. on letters into individivual character +
-- combining accent. But recompose characters that we want to treat
-- as units and get caught in the crossfire.
function export.decompose(text)
return (rsub(toNFD(text), ".[" .. AC .. CARON .. OGONEK .. "]", recomposer))
end
-- Decompose as in export.decompose(), but also canonicalize circumflex to
-- inverse breve in case it accidentally gets used.
function export.canon_decompose(text)
return (export.decompose(text):gsub(CFLEX, INVBREVE))
end
function export.assert_decomposed(text)
assert(text == export.canon_decompose(text))
end
function export.first_palatalization(stem)
stem = rsub(stem, "...$", {["zdz"]="ždž"})
stem = rsub(stem, "..$", {["sk"]="šč", ["zg"]="ždž", ["dz"]="ž", ["sc"]="šč"})
stem = rsub(stem, ".$", {["k"]="č", ["g"]="ž", ["x"]="š", ["c"]="č", ["ś"]="š"})
return stem
end
function export.second_palatalization(stem)
return rsub(stem, ".$", {["k"]="c", ["g"]="dz", ["x"]="ś"})
end
function export.iotate(stem)
stem = rsub(stem, "...$", {["zdz"]="ždž"})
stem = rsub(stem, "..$", {["sk"]="šč", ["zg"]="ždž", ["dz"]="ž", ["sc"]="šč"})
stem = rsub(stem, ".$", {
["b"]="bľ",
["c"]="č",
["d"]="ď",
["g"]="ž",
["k"]="č",
["l"]="ľ",
["m"]="mľ",
["n"]="ň",
["p"]="pľ",
["r"]="ř",
["s"]="š",
["ś"]="š",
["t"]="ť",
["v"]="vľ",
["x"]="š",
["z"]="ž",
})
if not rfind(stem, iotated_cons_c .. "$") then
stem = stem .. "j"
end
return stem
end
-- Check if word has a stress accent
function export.is_stressed(word)
export.assert_decomposed(word)
return rfind(word, stressed_accents_c)
end
-- Remove any stress accents from the word
function export.make_unstressed(word)
export.assert_decomposed(word)
return rsub(word, stressed_accents_c, "")
end
-- Check if word is nonsyllabic (has no vowels)
function export.is_nonsyllabic(word)
export.assert_decomposed(word)
return rfind(word, "^" .. non_vowels_c .. "*$")
end
-- Check if word is monosyllabic (has only one vowel)
function export.is_monosyllabic(word)
export.assert_decomposed(word)
return rfind(word, "^" .. non_vowels_c .. "*" .. vowels_c .. non_vowels_c .. "*$")
end
-- Set the accent in STEM to ACCENT, replacing any stressed accent already
-- there. If there isn't such an accent already then:
-- (1) If the accent is inverse breve (= old circumflex or short accent) or
-- double grave (= old short accent), put it on the first syllable;
-- (2) If the accent is tilde (= neoacute), put it on the last syllable;
-- (3) If the accent is a single grave (= old acute), put it on the vowel if
-- there's only one, otherwise don't add it as it can go anywhere.
-- Placing the accent will replace any unstressed accent already there
-- (specifically the macron).
--
-- In addition, if the accent is tilde (= neoacute), we put the accent on the
-- last syllable of the stem, regardless of any existing accent. The logic here
-- is that, in nouns at least, a neoacute on the stem that we request (i.e. not
-- already in the stem) is always retracted from the ending, and thus should
-- go on the last syllable if there is more than one. FIXME: May not apply to
-- verbs.
--
-- Also apply certain conversions to the result:
-- (1) Original short vowels e o ь ъ can't get a macron. Per Derksen 2008,
-- this also includes liquid diphthongs, which normally behave like
-- long vowels; cf. 'borzdà' "burrow" in class b, where you expect the
-- preceding vowel to be long if possible. However, we go against
-- Derksen in this respect when the first vowel is e or o because Czech,
-- Slovak and Polish show clear length distinctions (or reflections thereof)
-- in original pre-tonic syllables in class b vs. c. (Serbo-Croat reflects
-- length in both classes but this can be a later development due to
-- analogy.) Per Kortlandt, the metathesis of liquid diphthongs preceded
-- Dybo's law and (probably) the shortening of pre-tonic vowels.
-- (2) Original long vowels a i u y ě ę ǫ can't get a double grave, nor can
-- liquid diphthongs; instead, convert to inverse breve (circumflex accent).
-- (3) Original short vowels e o ь ъ not in liquid diphthongs can't receive a
-- tilde (neoacute) per the May 2019 discussion in
-- [[Wiktionary talk:About Proto-Slavic#Use the traditional accent symbols]];
-- instead we convert to single grave.
function export.set_accent(stem, accent)
export.assert_decomposed(stem)
-- string containing a hyphen is the value of UNK = unknown, and removes
-- all accents including macrons
if accent == "-" then
return rsub(stem, accents_c, "")
end
if accent == DOUBLEGR then
error("Double grave should not be specified as an accent; use inverted breve instead")
end
if not export.is_stressed(stem) and accent ~= TILDE and
(accent ~= GR or export.is_monosyllabic(stem)) then
-- If no stressed accent, put one on the first syllable, removing any
-- non-stress accent, i.e. macron (it doesn't matter which accent we put
-- as long as it's a stress accent, as it will be overwritten in the
-- next clause). But don't do this if accent is a tilde (no point, it
-- will be ignored and removed in the next clause), and if the accent is
-- a grave, only do this if the stem is monosyllabic.
stem = rsub(stem, "^(.-" .. vowels_c .. ")" .. accents_c .. "*",
"%1" .. INVBREVE)
end
if accent == TILDE then
-- If a tilde, cancel out any existing stressed accent and put the tilde
-- on the last syllable. (FIXME, might not apply to verbs.) Later on
-- we will conver this to a single grave if it's on a short monophthong.
stem = export.make_unstressed(stem)
stem = rsub(stem, "^(.*" .. vowels_c .. ")" .. accents_c .. "*",
"%1" .. TILDE)
else
-- Otherwise just replace the stressed accent, if any, with the given
-- accent. There will always be such an accent except in multisyllabic
-- words where the accent is a single grave; in other circumstances
-- we added an accent on the first syllable if it was missing.
stem = rsub(stem, stressed_accents_c .. "+", accent)
end
if accent == MACRON then
-- hack to handle liquid diphthongs: generate two macrons, since the
-- following regex will remove one.
stem = rsub(stem, "([eo])" .. MACRON .. "([lr]" .. cons_c .. ")",
"%1" .. MACRON .. MACRON .. "%2")
stem = rsub(stem, "(" .. short_vowels_c .. ")" .. MACRON, "%1")
end
-- Convert inverse breve after short vowel not in liquid diphthong to
-- double grave.
if rfind(stem, short_vowels_c .. INVBREVE) and
not rfind(stem, short_vowels_c .. INVBREVE .. "[lr]" .. cons_c) then
stem = rsub(stem, INVBREVE, DOUBLEGR)
end
-- Convert tilde after short vowel not in liquid diphthong to single grave.
if rfind(stem, short_vowels_c .. TILDE) and
not rfind(stem, short_vowels_c .. TILDE .. "[lr]" .. cons_c) then
stem = rsub(stem, TILDE, GR)
end
return stem
end
-- Infer the accentual pattern for a given unstressed word and accent pattern.
-- Return a list of possibilities (possibly empty if no accent could be inferred,
-- possibly containing more than one entry if multiple accentual patterns are
-- possible, e.g. with *voľa-type nouns), each of which is a three-entry list of
-- {stem, desinence, final_accent}.
local function infer_accent(word, ap)
assert(not export.is_stressed(word))
local possible_accents = {}
local stem, desinence, final_accent = export.split_stem_desinence(word)
if ap == "a" then
if export.is_monosyllabic(stem) then
table.insert(possible_accents, {export.set_accent(stem, GR), desinence, final_accent})
end
elseif ap == "b" then
if export.is_nonsyllabic(stem) then
table.insert(possible_accents, {stem, desinence, GR})
elseif desinence == "ь" or desinence == "ъ" then
table.insert(possible_accents, {export.set_accent(stem, TILDE), desinence, final_accent})
else
table.insert(possible_accents, {stem, desinence, GR})
if desinence == "a" and rfind(stem, iotated_cons_c .. "$") then
-- *voľa-type accent
table.insert(possible_accents, {export.set_accent(stem, TILDE), desinence, final_accent})
end
end
elseif ap == "c" then
if export.is_nonsyllabic(stem) then
table.insert(possible_accents, {stem, desinence, INVBREVE})
elseif desinence == "a" then
table.insert(possible_accents, {stem, desinence, GR})
else
table.insert(possible_accents, {export.set_accent(stem, INVBREVE), desinence, final_accent})
end
end
return possible_accents
end
-- If WORD is unstressed, add the appropriate accent for the accent pattern AP
-- if possible (it won't be possible with accent pattern a in words with a
-- multisyllabic stem). If WORD is stressed, check that the accent on the word
-- is appropriate for the accent pattern, and throw an error if not. In either
-- case, return three values, STEM, DESINENCE and FINAL_ACCENT, which when
-- concatenated together produce the original word.
function export.auto_accent_and_check_accents(word, ap)
local unstressed = not export.is_stressed(word)
if unstressed then
local possible_accents = infer_accent(word, ap)
if #possible_accents == 0 then
return export.split_stem_desinence(word)
end
local first = possible_accents[1]
local stem, desinence, final_accent = first[1], first[2], first[3]
return stem, desinence, final_accent
else
local uword = export.make_unstressed(word)
local possible_accents = infer_accent(uword, ap)
if #possible_accents == 0 then
return export.split_stem_desinence(word)
end
local possible_words = {}
for _, split_possible in ipairs(possible_accents) do
local stem, desinence, final_accent = split_possible[1], split_possible[2], split_possible[3]
local possible_word = stem .. desinence .. final_accent
if possible_word == word then
return stem, desinence, final_accent
end
table.insert(possible_words, possible_word)
end
error("For accent pattern " .. ap .. ", accented lemma should look like " ..
table.concat(possible_words, " or ") .. " but is actually " .. word)
end
end
function export.split_stem_desinence(word)
export.assert_decomposed(word)
local stem, desinence, final_accent = rmatch(word, "^(.-)(.)(" .. accents_c .. "?)$")
if not stem or not desinence then
error("Something wrong with '" .. word .. "', probably too short")
end
return stem, desinence, final_accent
end
return export
trbhowihl2x6yhj4rfz96tyq80m7qv4
ကဏ္ဍ:ထာမ်ပလိက်အူရဒူအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်
14
295032
399879
395534
2026-07-23T01:24:12Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်အူရဒူဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်အူရဒူအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
395534
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏအူရဒူဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|အ]]
ekrxxcwm0vae521jxssn1p676o7wha8
399881
399879
2026-07-23T01:24:59Z
咽頭べさ
33
399881
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်အူရဒူအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|အ]]
a3mhwk06gjkdsx3jvcltd7kwuvb3dpk
ကဏ္ဍ:ထာမ်ပလိက်အူရဒူအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
295034
399880
395536
2026-07-23T01:24:35Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏအူရဒူဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်အူရဒူအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
395536
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်အူရဒူဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|အ]]
2ljf39od7qq70fmyhmlr6igrs2u0dft
ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်
14
295062
399876
395568
2026-07-23T01:22:22Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်မတဳလဳဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
395568
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏမတဳလဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]]
dfi8e8nfu29pdua4jg1akg7488xyjn0
399878
399876
2026-07-23T01:23:25Z
咽頭べさ
33
399878
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]]
5swm9g99hm7h0zwbi4l6m31j98xch4i
ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
295063
399877
395569
2026-07-23T01:23:00Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏမတဳလဳဂမၠိုၚ်]] ဇရေင် [[ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
395569
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်မတဳလဳဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]]
p4a62qy7vnm32nhelm1aeo9mstfky2h
ကဏ္ဍ:ထာမ်ပလိက်ခေန်ချူဝါအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်
14
295405
399841
397515
2026-07-21T10:11:31Z
咽頭べさ
33
399841
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ခေန်ချူဝါအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ခ]]
k7cghjvxhv05x4yuaojhco0210fa9wa
ကဏ္ဍ:ယူနဳကုဒ် ဗါမုမ်
14
297445
399719
2026-07-20T14:05:41Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]"
399719
wikitext
text/x-wiki
[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]
ak38aisd37thdp65kqkgyaqadjtvgs8
အဆက်လက္ကရဴ:ယူနဳကုဒ်/အက္ခရ်ထ္ၜးကဆံၚ်ရမျာၚ်နကဵုမပလေဝ်ပလေတ်ဂမၠိုၚ်
100
297446
399720
2026-07-20T14:06:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{Unicode character list header}} {{Unicode character list}}"
399720
wikitext
text/x-wiki
{{Unicode character list header}}
{{Unicode character list}}
ttzawwpka9qk1qjw50j3ep2eaqycaqw
ကဏ္ဍ:ယူနဳကုဒ် အက္ခရ်ထ္ၜးကဆံၚ်ရမျာၚ်နကဵုမပလေဝ်ပလေတ်ဂမၠိုၚ်
14
297447
399721
2026-07-20T14:07:58Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]"
399721
wikitext
text/x-wiki
[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]
ak38aisd37thdp65kqkgyaqadjtvgs8
꜀
0
297448
399722
2026-07-20T14:09:05Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399722
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜁
0
297449
399723
2026-07-20T14:09:27Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399723
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜂
0
297450
399724
2026-07-20T14:09:39Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399724
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜃
0
297451
399725
2026-07-20T14:09:50Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399725
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜄
0
297452
399726
2026-07-20T14:10:01Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399726
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜅
0
297453
399727
2026-07-20T14:10:14Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399727
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜆
0
297454
399728
2026-07-20T14:10:27Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399728
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜇
0
297455
399729
2026-07-20T14:10:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399729
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜈
0
297456
399730
2026-07-20T14:10:47Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399730
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜉
0
297457
399731
2026-07-20T14:11:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399731
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜊
0
297458
399732
2026-07-20T14:11:14Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399732
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜋
0
297459
399733
2026-07-20T14:15:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399733
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜌
0
297460
399734
2026-07-20T14:15:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399734
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜍
0
297461
399735
2026-07-20T14:15:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399735
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜎
0
297462
399736
2026-07-20T14:15:54Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399736
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜏
0
297463
399737
2026-07-20T14:16:16Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399737
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜐
0
297464
399738
2026-07-20T14:16:39Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399738
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜑
0
297465
399739
2026-07-20T14:16:55Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399739
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜒
0
297466
399740
2026-07-20T14:17:05Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399740
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜓
0
297467
399741
2026-07-20T14:17:19Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399741
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜔
0
297468
399742
2026-07-20T14:17:31Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399742
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜕
0
297469
399743
2026-07-20T14:19:09Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399743
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꜖
0
297470
399744
2026-07-20T14:19:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399744
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜗ
0
297471
399745
2026-07-20T14:19:58Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399745
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜘ
0
297472
399746
2026-07-20T14:20:28Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399746
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜟ
0
297473
399747
2026-07-20T14:20:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399747
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜙ
0
297474
399748
2026-07-20T14:21:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399748
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜚ
0
297475
399749
2026-07-20T14:22:16Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399749
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜛ
0
297476
399750
2026-07-20T14:24:28Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399750
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜜ
0
297477
399751
2026-07-20T14:25:36Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399751
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜝ
0
297478
399752
2026-07-20T14:26:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399752
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꜞ
0
297479
399753
2026-07-20T14:26:32Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399753
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
အဆက်လက္ကရဴ:ယူနဳကုဒ်/ဗီုပြၚ်ဂၞန်သၚ်္ချာအိန္ဒိယသာမညဂမၠိုၚ်
100
297480
399755
2026-07-20T14:33:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{Unicode character list header}} {{Unicode character list}}"
399755
wikitext
text/x-wiki
{{Unicode character list header}}
{{Unicode character list}}
ttzawwpka9qk1qjw50j3ep2eaqycaqw
ကဏ္ဍ:ယူနဳကုဒ် ဗီုပြၚ်ဂၞန်သၚ်္ချာအိန္ဒိယသာမညဂမၠိုၚ်
14
297481
399756
2026-07-20T14:35:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]"
399756
wikitext
text/x-wiki
[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]
ak38aisd37thdp65kqkgyaqadjtvgs8
꠰
0
297482
399757
2026-07-20T14:38:40Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399757
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠱
0
297483
399758
2026-07-20T14:39:14Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399758
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠲
0
297484
399759
2026-07-20T14:39:34Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399759
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠳
0
297485
399760
2026-07-20T14:42:24Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399760
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠴
0
297486
399761
2026-07-20T14:42:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399761
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠵
0
297487
399762
2026-07-20T14:43:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399762
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠶
0
297488
399763
2026-07-20T14:43:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399763
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠷
0
297489
399764
2026-07-20T14:44:08Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399764
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠸
0
297490
399765
2026-07-20T14:44:19Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399765
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
꠹
0
297491
399766
2026-07-20T14:44:29Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399766
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
အဆက်လက္ကရဴ:ယူနဳကုဒ်/သၠဲပ္တိတ်မဳတဳ မာယေတ်ဂမၠိုၚ်
100
297492
399767
2026-07-20T14:48:28Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{Unicode character list header}} {{Unicode character list}}"
399767
wikitext
text/x-wiki
{{Unicode character list header}}
{{Unicode character list}}
ttzawwpka9qk1qjw50j3ep2eaqycaqw
ကဏ္ဍ:ယူနဳကုဒ် သၠဲပ္တိတ်မဳတဳ မာယေတ်ဂမၠိုၚ်
14
297493
399768
2026-07-20T14:49:08Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]"
399768
wikitext
text/x-wiki
[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]
ak38aisd37thdp65kqkgyaqadjtvgs8
꫶
0
297494
399769
2026-07-20T14:55:00Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399769
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫠ
0
297495
399771
2026-07-20T15:13:21Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399771
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ကဏ္ဍ:ဗျဉ်အခဝ်မဳတဳ မာယေတ်ဂမၠိုၚ်
14
297496
399772
2026-07-20T15:13:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]"
399772
wikitext
text/x-wiki
[[ကဏ္ဍ:ဒၞာဲအခဝ်ယူနဳကုဒ်ဂမၠိုၚ်]]
ak38aisd37thdp65kqkgyaqadjtvgs8
ꫡ
0
297497
399773
2026-07-20T15:14:10Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399773
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫢ
0
297498
399774
2026-07-20T15:14:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399774
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫣ
0
297499
399775
2026-07-20T15:14:32Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399775
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫤ
0
297500
399776
2026-07-20T15:14:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399776
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫥ
0
297501
399777
2026-07-20T15:15:15Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399777
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫦ
0
297502
399778
2026-07-20T15:15:32Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399778
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫧ
0
297503
399779
2026-07-20T15:18:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399779
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫨ
0
297504
399780
2026-07-20T15:19:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399780
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫩ
0
297505
399781
2026-07-20T15:19:20Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399781
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫪ
0
297506
399782
2026-07-20T15:19:33Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399782
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫫ
0
297507
399783
2026-07-20T15:19:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399783
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫬ
0
297508
399784
2026-07-20T15:19:59Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399784
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫭ
0
297509
399785
2026-07-20T15:20:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399785
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫮ
0
297510
399786
2026-07-20T15:28:14Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399786
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ꫯ
0
297511
399787
2026-07-20T15:28:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{character info}} ==မအရေဝ်ပံၚ်ကောံ== ===သၚ်္ကေတ=== {{mul-symbol}}"
399787
wikitext
text/x-wiki
{{character info}}
==မအရေဝ်ပံၚ်ကောံ==
===သၚ်္ကေတ===
{{mul-symbol}}
k3rct8ujozuc9s9nxcytnm2etoedwr9
ထာမ်ပလိက်:ru-noun-table
10
297512
399789
2026-07-21T01:44:35Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{#invoke:ru-noun|show}}</includeonly><noinclude>{{documentation}}</noinclude>"
399789
wikitext
text/x-wiki
<includeonly>{{#invoke:ru-noun|show}}</includeonly><noinclude>{{documentation}}</noinclude>
jk8o3go7sise77glwo2hdt9739pylgj
ထာမ်ပလိက်:ru-noun-table/documentation
10
297513
399790
2026-07-21T01:53:40Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|Module:ru-noun}} This is the new template for creating a Russian noun declension table. ==Parameters== ; {{para|1}} : Stress pattern, one of <code>a b c d e f b' d' f' f''</code>. See [[Appendix:Russian stress patterns]]. It can be omitted; to do so, leave out the argument entirely (i.e. shift all the remaining arguments down one). If omitted, defaults to <code>a</code> if the..."
399790
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:ru-noun}}
This is the new template for creating a Russian noun declension table.
==Parameters==
; {{para|1}}
: Stress pattern, one of <code>a b c d e f b' d' f' f''</code>. See [[Appendix:Russian stress patterns]]. It can be omitted; to do so, leave out the argument entirely (i.e. shift all the remaining arguments down one). If omitted, defaults to <code>a</code> if the lemma stress is on the stem, <code>b</code> if the lemma stress is on the ending or if an explicitly specified declension is accented. (Also defaults to <code>b</code> in <code>-ёнок</code> and <code>-ёночек</code> nouns and <code>+ой</code> adjectival nouns, and defaults to <code>d</code> in stressed <code>-и́н</code> nouns.)
; {{para|2}}
: Lemma with appropriately placed accent(s); i.e. the nominative singular, or the nominative plural if the noun is a plurale tantum. However, if an explicit declension is specified, this should be just the stem (in this case, the declension usually looks like an ending, and the stem is the portion of the lemma minus the ending). In the first argument set (i.e. first set of arguments separated by <code>or</code>), defaults to page name; in later sets, defaults to lemma of previous set. A plural form can be given, and causes argument n= to default to n=p (plurale tantum). Normally, an accent is required if multisyllabic, and unaccented monosyllables will automatically be stressed; prefix with <code>*</code> to override both behaviors. See section below on auto-accenting. May be followed by <code>//</code> and a manual transliteration; see section below.
; {{para|3}}
: Declension modifiers; see below. This contains any extra information needed to properly decline the noun.
; {{para|4}}
: Specify a special plural stem; defaults to the stem of the lemma. This is only needed for a few nouns whose plural is based off of a different stem, e.g. {{m|ru|у́хо||ear}} with nominative plural {{m|ru|у́ши}}; {{m|ru|не́бо||sky, heaven}} with nominative plural {{m|ru|небеса́}}; or {{m|ru|хозя́ин||owner, landlord}} with nominative plural {{m|ru|хозя́ева}}. It is not needed if only the endings are irregular, nor if the only difference between singular and plural stems is a ''ё'' in place of an unstressed ''е'' in the lemma, as with {{m|ru|седло́||saddle}} with nominative plural {{m|ru|сёдла}}. Normally, the plural stem needs a stress mark if multisyllabic, as with the lemma. May be followed by <code>//</code> and a manual transliteration; see section below.
; {{para|n}}
: Number restriction: <code>sg</code> for singular-only, <code>pl</code> for plural-only, <code>both</code> for both. Defaults to both unless the lemma is plural, in which case it defaults to plural-only. (Only the first letter matters in the values for this argument, so for example <code>s</code> and <code>sing</code> are alternatives to <code>sg</code>.)
; {{para|a}}
: Animacy: <code>an</code> for animate, <code>in</code> for inanimate, <code>bi</code> or <code>ai</code> for bianimate (listing animate first when used by {{temp|ru-noun+}}), <code>ia</code> for bianimate (listing inanimate first when used by {{temp|ru-noun+}}); defaults to inanimate. (You can also use <code>a</code> or <code>anim</code> for animate, <code>i</code> or <code>inan</code> for inanimate, <code>b</code> or <code>both</code> for bianimate with animate listed first.)
; {{para|title}}
: Override the table title.
; {{para|nom_sg}}, {{para|gen_sg}}, {{para|dat_sg}}, {{para|acc_sg}}, {{para|ins_sg}}, {{para|pre_sg}}, {{para|nom_pl}}, {{para|gen_pl}}, {{para|dat_pl}}, {{para|acc_pl}}, {{para|ins_pl}}, {{para|pre_pl}}, {{para|par}}, {{para|loc}}, {{para|voc}}, {{para|count}}, {{para|pauc}}
: Override one or more declensional forms (nominative, genitive, dative, accusative, instrumental, prepositional, partitive, locative, vocative (singular or plural), plus the count form and paucal). Alternatives may be separated by commas. You can include one or more <code>~</code> characters anywhere in the override, which will replaced by the singular or plural stem, appropriately; or you can use <code>~~</code>, which will be replaced by the unstressed version of the appropriate stem. You can also include <code>+</code> in {{para|par}} or {{para|loc}}, and if it is at the beginning of a word it will be replaced by the "expected" form for these cases (same as dative singular for the partitive, stress-shifted dative singular for the locative). Overridden forms, including comma-separated alternatives, will automatically be linked. Certain trailing symbols are recognized automatically; they will be superscripted and do not interfere with linking. See section below on usage notes. In more complex cases (e.g. with parens around a word), you should manually put brackets around a word to link it (stress marks in such words are handled correctly). Normally, multisyllabic words in overrides need a stress mark, as with the lemma. May be followed by <code>//</code> and a manual transliteration; see section below.
; {{para|suffix}}
: Add a suffix such as ся to all forms. This is useful in cases like {{m|ru|уча́щийся||student}}, where the part before -ся needs to be declined. May be followed by <code>//</code> and a manual transliteration; see section below.
; {{para|prefix}}
: Add a prefix to all forms. Present for completeness but less useful than {{para|suffix}} because the prefix can simply be included in the lemma. May be followed by <code>//</code> and a manual transliteration; see section below.
===Footnote symbols===
A system is in place for inserting usage notes into declension tables, in the form of footnotes. Footnote symbols attached to the end of a manual override are recognized automatically; they are automatically superscripted and do not interfere with linking. Examples of such symbols are <code>*</code>, <code>@</code>, <code>~</code> and various other ASCII symbols; numbers; <code>_</code>, which is automatically converted to a space; and most Unicode symbols (<code>§</code>, <code>¤</code>, <code>†</code>, <code>‡</code>, <code>⁕</code>, etc.). You can also insert these symbols using parameters such as {{para|pltail}}. The usage note itself is inserted using {{para|notes}}.
; {{para|notes}}, {{para|notes2}}, {{...}}
: Usage note(s) to insert into the table. Footnote symbols at the beginning of the note are automatically superscripted.
; {{para|pltail}}
: Specify text to append directly to the end of plural entries with more than one form (except those with explicit overrides). Normally used to add a footnote symbol to those entries, to add a usage note to alternate plural forms.
; {{para|sgtail}}
: Same but for singular entries.
; {{para|pltailall}}
: Like {{para|pltail}} but appends to all plural entries (except those with explicit overrides). Normally used to add a footnote symbol, in order to add a usage note about the plural forms.
; {{para|sgtailall}}
: Same but for singular entries.
; {{para|CASE_NUM_tail}}
: Append a footnote symbol to the last form for a particular case/number combination. Note that this differs from {{para|sgtail}} and {{para|pltail}} in that it will be appended even if there's only one form. The possible values of CASE_NUM are the same as for overrides.
; {{para|CASE_NUM_tailall}}
: Same but append to all forms, as with {{para|pltailall}} and {{para|sgtailall}}.
===Conjectural/disused forms===
A system is in place for marking particular forms as conjectural or disused; these are forms that are described in Russian grammar books (such as those of A.A. Zaliznyak) as {{m|ru|затрудни́тельный}}, literally "difficult" or "awkward". Forms are marked as such either by putting a <code>*</code> at the beginning of a word in a manual override or using parameters such as {{para|plhypall|y}} to mark all plural forms as conjectural/disused (<code>hyp</code> in the parameter name = "hypothetical"). These <code>*hyp*</code> parameters are exactly parallel to the <code>*tail*</code> parameters above. The most useful such parameters are {{para|plhypall|y}} as described previously, and {{para|CASE_NAME_tailall|y}} to mark all forms of a given case/number combination as conjectural/disused.
===Declension modifiers===
The third parameter consists of any additional modifiers needed to properly decline the noun. There are several different modifiers. If you need to specify more than one modifier, just jam them all together without any spaces between and in any order. The following modifiers are the most common:
====Gender====
The gender spec indicates the gender of the noun. Normally, this can be omitted and is autodetected from the ending of the noun. However, it is required in some cases, e.g. with lemmas ending in ''-ь''. If present, it should be one of <code>m</code> (masculine), <code>f</code> (feminine), <code>n</code> (neuter) or <code>3f</code> (third-declension feminine; see below). The gender is required in the following cases:
# if the lemma ends in ''-ь'';
# in regular (not adjectival) nouns, if the lemma is plural;
# for masculine animate nouns with the neuter ending -о in the nominative singular (e.g. {{m|ru|солове́йко||nightingale}}, {{m|ru|мазло́||sloppy person}});
# in {{temp|ru-noun+}} whenever the actual gender disagrees with the normal gender of the nominative singular ending (e.g. {{m|ru|дя́дя||uncle}}).
In other cases, the gender is ignored.
<code>3f</code> is the same as <code>f</code> but in the case of a plural lemma in ''-и'', it causes a third-declension feminine with singular in ''-ь'' to be detected rather than a first-declension feminine with singular in ''-а'' or ''-я'' (used e.g. for {{m|ru|но́вости}} and {{m|ru|сла́сти}}).
====Reducibility====
The spec <code>*</code> indicates that the noun is "reducible". A reducible noun has an alternation between a ''е'', ''ё'' or ''о'' before the last stem consonant in some forms, and no such vowel in other forms. Such nouns are of two types:
# Nouns where the extra vowel appears in the nominative singular but not in other forms. These are either masculine nouns ending in a consonant, or masculine or feminine nouns ending in ''-ь''. An example of the former is {{m|ru|коне́ц||end}} (genitive singular {{m|ru|конца́}}, nominative plural {{m|ru|концы́}}). Examples of the latter are masculine {{m|ru|ого́нь||fire}} (genitive singular {{m|ru|огня́}}, masculine {{m|ru|гре́бень||comb}} (genitive singular {{m|ru|гре́бня}}), feminine {{m|ru|любо́вь||love}} (genitive singular {{m|ru|любви́}}), and feminine {{m|ru|вошь||louse}} (genitive singular {{m|ru|вши}}).
# Nouns where the extra vowel appears in the genitive plural but not in other forms. These are feminine or neuter nouns ending in a vowel. Examples are feminine {{m|ru|ко́шка||cat}} (genitive plural {{m|ru|ко́шек}}), neuter {{m|ru|се́рдце||heart}} (genitive plural {{m|ru|серде́ц}}).
Note that when the vowel disappears, sometimes a ''ь'' or ''й'' appears in its place, e.g. {{m|ru|па́лец||finger}} (genitive singular {{m|ru|па́льца}}), {{m|ru|инди́ец||Indian}} (genitive singular {{m|ru|инди́йца}}), or other changes happen, e.g. {{m|ru|воробе́й||sparrow}} (genitive singular {{m|ru|воробья́}}). When a vowel appears, sometimes it's ''е'', sometimes ''ё'' and sometimes ''о'', and sometimes a ''ь'' disappears. It turns out that all these changes are predictable, and are automatically handled by the module.
====Adjectival nouns====
These are nouns that are declined as if they were an adjective. Examples are masculine {{m|ru|ру́сский||a Russian}} (genitive singular {{m|ru|ру́сского}}), feminine {{m|ru|ва́нная||bathroom}} (genitive singular {{m|ru|ва́нной}}), neuter {{m|ru|моро́женое||ice cream}} (genitive singular {{m|ru|моро́женого}}) and plural-only {{m|ru|да́нные||facts, data}} (genitive plural {{m|ru|данных}}). To indicate this, use the code <code>+</code>.
====Nouns with alternation between е and ё====
Some nouns have an alternation between unstressed ''е'' and stressed ''ё''. If the ''ё'' appears in the lemma, the module will automatically convert it to ''е'' when it becomes unstressed, e.g. {{m|ru|галдёж||clatter, din}} (genitive singular {{m|ru|галдежа́}}). But sometimes the ''е'' appears in the lemma, and ''ё'' appears in other forms. In this case, use <code>;ё</code> to indicate this alternation. An example is {{m|ru|седло́||saddle}} (nominative plural {{m|ru|сёдла}}).
====Anomalous plural endings====
Use <code>(1)</code> to indicate a particular sort of anomalous nominative plural ending where masculine nouns take the neuter plural ''-а'' or ''-я'' instead of expected ''-ы'' or ''-и'', and neuter nouns take the masculine plural ''-ы'' or ''-и'' instead of expected ''-а'' or ''-я''.
Use <code>(2)</code> to indicate a particular sort of anomalous genitive plural ending where masculine nouns take the feminine/neuter null ending (which may manifest as no written ending or as ''-ь'' or ''-й'') instead of expected ''-ов/-ев/-ёв'', while neuter nouns take the masculine ending ''-ов/-ев/-ёв'' instead of the expected null ending, and feminine hard-stem nouns take the soft-stem ending ''-ей/-ёй'' instead of the expected null ending. When the variant code <code>-ья</code> is given (see below), the code <code>(2)</code> indicates a feminine-style genitive plural ending of ''-ей'' instead of masculine ''-ьев/-ьёв''. An example of this is {{m|ru|де́верь||brother-in-law (husband's brother)}}, with nominative plural {{m|ru|деверья́}} (hence it needs variant code <code>-ья</code>) and genitive plural {{m|ru|девере́й}} (hence it needs code <code>(2)</code>). Since this noun ends in ''-ь'', it also needs the gender code <code>m</code>; the full spec is written <code>m-ья(2)</code>, with the three codes jammed together (other orders are possible for the codes).
====Older stuff to be cleaned up====
One of the following for regular nouns:
# (blank)
# GENDER
# <code>-</code>VARIANT
# GENDER<code>-</code>VARIANT
# DECLTYPE
# DECLTYPE/DECLTYPE
# <code>$</code> {{qualifier|for indeclinable words, especially in multi-word expressions}}
# You can also append one or more of the special-case markers <code>(1)</code>, <code>(2)</code>, <code>*</code> or <code>;ё</code> to any of the above.
For adjectival nouns, one of the following:
# <code>+</code>
# <code>+ь</code>
# <code>+short</code>, <code>+mixed</code> or <code>+proper</code>
# <code>+</code>DECLTYPE
VARIANT specifies declension variants that override the normal declension in various ways: See also special cases <code>(1)</code> and <code>(2)</code> for specifying other types of plural variants.
# The <code>-ья</code> variant overrides the normal declension with the special plural declension with nominative plural -ья.
# The <code>-ин</code> variant is for animate masculines ending in -ин with nominative plural in -е. Most such nouns end in -анин or -янин, and these are autodetected, but other nouns in this declension such as {{m|ru|боя́рин||[[boyar]]}} need an explicit variant annotation.
# The <code>-ишко</code> variant is for inanimate diminutive masculines (not neuters) ending in -шко (usually -ишко), with colloquial feminine forms in some of the singular cases, e.g. {{m|ru|доми́шко||small house}}. Special case <code>(1)</code> must be specified along with this variant.
# The <code>-ище</code> variant is for animate augmentative masculines (not neuters) ending in -ище, with colloquial feminine forms in some of the singular cases, e.g. {{m|ru|волчи́ще||large, mature wolf}}. Special case <code>(1)</code> must be specified along with this variant.
DECLTYPE is an explicit declension type. Normally you shouldn't use this, and should instead let the declension type be autodetected based on the ending. See the table below for the list of declension types (which normally have the form of the nominative singular ending). When an explicit declension type is provided, the lemma field should be just the stem, without the ending.
For adjectival nouns, you should normally supply just <code>+</code> and let the ending determine the declension; supply <code>+ь</code> in the case of a possessive adjectival noun in -ий, which has an extra -ь- in most endings compared with normal adjectival nouns in -ий, but which can't be distinguished based on the nominative singular. You can also supply <code>+short</code>, <code>+mixed</code> or <code>+proper</code>, which constrains the declension appropriately but still autodetects the gender-specific and stress-specific variant. If you do supply a specific declension type, as with regular nouns you need to omit the ending from the lemma field and supply just the stem. Possibilities are <code>+ый</code>, <code>+ое</code>, <code>+ая</code>, <code>+ій</code>, <code>+ее</code>, <code>+яя</code>, <code>+ой</code>, <code>+о́е</code>, <code>+а́я</code>, <code>+ьій</code>, <code>+ье</code>, <code>+ья</code>, <code>+-short</code> or <code>+#-short</code> (masc), <code>+о-short</code>, <code>+о-stressed-short</code> or <code>+о́-short</code>, <code>+а-short</code>, <code>+а-stressed-short</code> or <code>+а́-short</code>, and similar for <code>-mixed</code> and <code>-proper</code> (except there aren't any stressed mixed declensions).
The DECLTYPE/DECLTYPE form is used for nouns with one declension in the singular and a different one in the plural (termed ''mixed declensions'' or ''slash declensions''). This is intended for variations that <code>-ья</code> and special cases <code>(1)</code> and <code>(2)</code> below don't cover, e.g. <code>о/ь-m</code> to decline the singular with class <code>о</code> and the plural with class <code>ь-m</code> (as for {{m|ru|коле́но||knee}}). There is no autodetection of mixed declensions, and thus the lemma field needs to contain the bare stem. See examples below.
Special-case markers:
* <code>(1)</code> for Zaliznyak-style alternate nominative plural ending: -а or -я for masculine, -и or -ы for neuter
* <code>(2)</code> for Zaliznyak-style alternate genitive plural ending: none/-ь/-й for masculine, -ей for feminine, -ов/-ёв/-ев for neuter, -ей for declensional variant <code>-ья</code>
* <code>*</code> for reducibles (nom sg or gen pl has an extra vowel before the final consonant as compared with the stem found in other cases)
* <code>;ё</code> for Zaliznyak-style alternation between last е in stem and ё
===Declension classes===
"Class" is the form used with the modern-style tables ({{temp|ru-noun-table}}), while "old class" is used with old-style/pre-reform tables ({{para|old|1}}). Note that explicit declension classes aren't normally required, as the declension can usually be autodetected.
{|class=wikitable style="text-align: center;"
! Class !! Old class !! Nom sg !! Nom pl !! Gen pl !! Declension !! Typical gender !! Hardness !! Examples !! Notes
|-
| (blank), <code>#</code> || <code>ъ</code> || none || ы/и || ов, [шщчж]ей || 2nd || Masculine || Hard || заво́д, язы́к, ча́с || gen pl -ей after sibilants
|-
| <code>-а</code>, <code>#-а</code> || <code>ъ-а</code> || none || а || ов, [шщчж]ей || 2nd || Masculine || Hard || рука́в/рукава́, по́езд/поезда́ || gen pl -ей after sibilants
|-
| <code>-ья</code>, <code>#-ья</code> || <code>ъ-ья</code> || none || ья || ьёв/ьев || 2nd || Masculine || Hard || дру́г/друзья́ ||
|-
| <code>ин</code> || <code>инъ</code> || ин || е || none || 2nd || Masculine || Hard || англича́нин, христиани́н ||
|-
| <code>ёнок</code>, <code>онок</code>, <code>енок</code> || <code>ёнокъ</code>, <code>онокъ</code>, <code>енокъ</code> || ёнок/о́нок || я́та/а́та || я́т/а́т || 2nd || Masculine || Hard || телёнок, внучо́нок ||
|-
| <code>ёночек</code>, <code>оночек</code>, <code>еночек</code> || <code>ёночекъ</code>, <code>оночекъ</code>, <code>еночекъ</code> || ёночек/о́ночек || я́тки/а́тки || я́ток/а́ток || 2nd || Masculine || Hard || цыплёночек, мышо́ночек ||
|-
| colspan=2|<code>ь-m</code> || ь || и || ей || 2nd || Masculine || Soft || до́ждь, ру́бль, ка́мень ||
|-
| colspan=2|<code>ь-я</code> || ь || я || ей || 2nd || Masculine || Soft || кре́ндель/кренделя́ ||
|-
| colspan=2|<code>й</code> || й || и || ёв/ов || 2nd || Masculine || Palatal || ча́й, геро́й, ге́ний || includes -ий nouns (old-style -ій)
|-
| colspan=2|<code>й-я</code> || й || я || ёв/ов || 2nd || Masculine || Palatal || кра́й || includes -ий nouns (old-style -ій)
|- style="border-top: 5px solid var(--wikt-palette-blue,blue);"
| colspan=2|<code>а</code> || а || ы/и || none, [шщчж]е́й || 1st || Feminine || Hard || соба́ка, голова́ || gen pl -е́й after sibilants (stressed only)
|-
| colspan=2|<code>я</code> || я || и || ь/й, е́й || 1st || Feminine || Soft || земля́, револю́ция || stressed gen pl -е́й except with vowel stems, otherwise -ь/-й; includes -ия nouns (old-style -ія) but not -ья nouns
|-
| colspan=2|<code>ья</code> || ья || ьи || ий, е́й || 1st || Feminine || Soft || судья́ || stressed gen pl -е́й (also patterns <code>d</code> and <code>d'</code>), unstressed -ий
|- style="border-top: 5px solid var(--wikt-palette-blue,blue);"
| colspan=2|<code>о</code> || о || а || none, е́й || 2nd || Neuter || Hard || стекло́, со́лнце || includes unstressed -е nouns after цшщчж; gen pl -е́й after sibilants (stressed only)
|-
| colspan=2|<code>о-и</code>, <code>о-ы</code> || о || ы/и || none || 2nd || Neuter || Hard || я́блоко/я́блоки, у́хо/у́ши || same as previous
|-
| colspan=2|<code>о-ья</code> || о || ья || ьёв/ьев || 2nd || Neuter || Hard || перо́/пе́рья, ши́ло/ши́лья, дно́/до́нья ||
|-
| colspan=2|<code>е</code>, <code>ё</code> || е/ё || я/а || ь/й, е́й || 2nd || Neuter || Soft || мо́ре, уче́ние || stressed gen pl -е́й except with vowel stems, otherwise -ь/-й; includes -ие/-иё nouns (old-style -іе/-іё) but not -ье/-ьё nouns
|-
| colspan=2|<code>е́</code> || е́ || я/а || ей, [и]й || 2nd || Neuter || Soft || бытие́, муде́ || nouns with stressed -е́ instead of -ё; includes nouns in -ие́ (old-style -іе́), which have gen pl in -ий
|-
| colspan=2|<code>ье</code>, <code>ьё</code> || ье/ьё || ья || ий, е́й || 2nd || Neuter || Soft || у́стье, копьё || stressed gen pl -е́й, unstressed -ий
|- style="border-top: 5px solid var(--wikt-palette-blue,blue);"
| colspan=2|<code>ь-f</code> || ь || и || ей || 3rd || Feminine || Soft || две́рь, гла́сность ||
|-
| colspan=2|<code>мя</code> || мя || мена || мён || 3rd || Neuter || ? || и́мя, пле́мя ||
|-
| colspan=2|<code>$</code> || none || none || none || Indeclinable || — || — || полпути́ ||
|}
===Auto-accenting and required accents===
Multisyllabic words in arguments (lemma, plural stem, overrides) normally need a stress mark in them (as in а́, ы́, ё or ѣ̈) to indicate the position of the stress; an error will occur otherwise. In multiword overrides, each multisyllabic word needs an accent. Accents are not required on monosyllabic words, which will automatically be stressed on their only vowel. You can override both accent errors and auto-accenting by prefixing the lemma with <code>*</code>. (Don't use this prefix on other arguments. If present on the lemma, it applies to all arguments.) This is useful when a word has no stress (e.g. unstressed suffixes) or when the stress is unknown.
As an exception, accents are not required when the accent pattern calls for ending stress (patterns <code>b</code>, <code>d</code>, <code>f</code> and variants in the singular, and patterns <code>b</code>, <code>c</code> and variants in the plural).
Multisyllabic stems automatically receive stress in certain circumstances:
# Patterns <code>d</code> and <code>f</code> and variants have ending stress in the singular (and thus normally in the lemma), but call for stem stress in the plural. Unless the lemma specifically includes a stress on the stem, it is placed according to rule: stem-final stress in pattern <code>d</code> and variants, stem-initial stress in pattern <code>f</code> and variants. Hence, {{m|ru|сапожо́к||boot}} (pattern <code>d</code>) gets plural сапо́жки, while {{m|ru|голова́||head}} (pattern <code>f</code>) gets plural го́ловы.
# If the accent pattern calls for ending stress in the genitive plural but the genitive plural has a null or non-syllabic ending, the last syllable of the stem is stressed -- regardless of the stem stress in other forms. Hence {{m|ru|голова́||head}} (pattern <code>f</code>) has nominative plural го́ловы but genitive plural голо́в. To override this, use an explicit {{para|gen_pl}} (or {{para|4}}) parameter, e.g. in {{m|ru|кирка́||pickaxe}} (pattern <code>b</code>) with genitive plural ки́рок or {{m|ru|де́ньги||money}} (pattern <code>e</code>) with genitive plural де́нег.
===Manual transliteration===
All parameters that accept Russian text can be followed by <code>//</code> and a manual transliteration. Transformations of the Russian text (e.g. reducing, dereducing, moving the stress) will appropriately be applied to the manual transliteration as well. Certain rules need to be respected concerning the manual transliteration, and will trigger errors if not. For example, the manual transliteration needs to have the same number of syllables as the Russian, and the manual transliteration of the lemma needs to have the same declensional ending (e.g. -а, -я, -о, -е, -ь), or rather its transliteration.
===Multiple sets of arguments, multiple words===
Multiple sets of arguments can be specified by separating them with an argument consisting solely of the word <code>or</code>. See the examples below.
You can also specify the declension of multi-word expressions such as {{m|ru|мя́гкий зна́к||soft sign}}, {{m|ru|ба́бье ле́то||Indian summer}}, {{m|ru|пау́к-во́лк||wolf spider}}, {{m|ru|Сент-Ви́нсент и Гренади́ны|tr=Sɛnt-Vínsɛnt i Grenadíny||Saint Vincent and the Grenadines}}, etc.
Multi-word nouns are specified by putting an underscore (<code>_</code>) between words separated by spaces, or a hyphen (<code>-</code>) between words separated by hyphens, or a joiner expression (<code>join:TEXT</code>) between words separated by arbitrary text.
The individual words appearing as lemma arguments can have links placed in them. This causes those individual words to link to the corresponding Wiktionary lemma page when appearing in the declension title (but not elsewhere in the declension table), and in the headword when used in conjunction with {{temp|ru-noun+}}. This is recommended especially for {{temp|ru-noun+}} and probably for {{temp|ru-noun-table}} too. The links can be simple links, even in the presence of accents. For example, you can write <code><nowiki>{{ru-noun-table|b|[[пау́к]]|-|e|[[во́лк]]|a=an}}</nowiki></code> to generate the declension of {{m|ru|пау́к-во́лк||[[wolf spider]]}}, and e.g. the link <code><nowiki>[[пау́к]]</nowiki></code> will automatically be converted to a link that displays пау́к but links to the page named паук (with the accent removed); it is as if you wrote <code><nowiki>[[паук#Russian|пау́к]]</nowiki></code>. See the examples for more information.
The named parameters above generally have per-word equivalents that let you control the value for individual words independently of the others. They are named the same as the overall parameters but have a number suffixed to them: <code>1</code> for the first word, <code>2</code> for the second word, etc.
; {{para|a1}}, {{para|a2}}, etc.
: Specify the animacy of an individual word. Default value for each word is the overall animacy specified by {{para|a}}. Primarily useful in case of expressions that mix animate and inanimate words.
; {{para|n1}}, {{para|n2}}, etc.
: Specify the number of an individual word. Default value for each word is the overall number specified by {{para|n}}. Primarily useful in case of expressions that mix singular and plural words, such as {{m|ru|Сент-Ви́нсент и Гренади́ны|tr=Sɛnt-Vínsɛnt i Grenadíny||Saint Vincent and the Grenadines}}. Note that if any word is specified using a plural lemma, the overall number defaults to plural.
; {{para|nom_sg1}}, {{para|nom_sg2}}, ...; {{para|gen_sg1}}, {{para|gen_sg2}}, ...; etc.
: Specify an override for a particular word rather than for the entire expression.
; {{para|pltail1}}, {{para|pltail2}}, ...; {{para|pltailall1}}, {{para|pltailall2}}, ...; etc.
: Specify a footnote symbol to attach to the end of a particular word rather than the entire expression. Generally this is not a good idea, and these parameters may be removed in the future.
; {{para|suffix1}}, {{para|suffix2}}, etc.
: Specify a suffix such as ся to attach to the end of all forms of a particular word.
; {{para|prefix1}}, {{para|prefix2}}, etc.
: Specify a prefix to attach to the beginning of all forms of a particular word. Present for completeness, but not especially useful; see discussion under {{para|prefix}} above.
==Basic examples==
===Example 1: A basic noun===
The noun {{m|ru|орео́л||halo}} belongs to accent pattern <code>a</code> (stem-stressed), which is the default, and hence does not need to be specified.
<code><nowiki>{{ru-noun-table|орео́л}}</nowiki></code>
produces
{{ru-noun-table|орео́л}}
===Example 2: An ending-stressed noun===
The noun {{m|ru|житие́||life}} belongs to accent pattern <code>b</code> (ending-stressed). This is automatically recognized because of the ending stress in the lemma. The accent shift onto the stem in the genitive plural жити́й is automatically handled.
<code><nowiki>{{ru-noun-table|житие́}}</nowiki></code>
produces
{{ru-noun-table|житие́}}
===Example 3: A noun with complex accent shifts===
The noun {{m|ru|голова́||head}} belongs to accent pattern <code>f</code> and has a complex pattern of accent shifts, with stress on the ending in singular голова́, on the first stem syllable in nominative plural го́ловы and on the second stem syllable in genitive plural голо́в. The accent pattern needs to be given explicitly but the accent shifts are automatically handled. In general the code is quite good about knowing how to automatically handle such cases.
<code><nowiki>{{ru-noun-table|f|голова́}}</nowiki></code>
produces
{{ru-noun-table|f|голова́}}
===Example 4: An animate noun needing a declensional variant===
The noun {{m|ru|боя́рин||boyar}} belongs to the declension class <code>ин</code>, with a singular suffix -ин that is missing in the plural and with nominative plural -е. These nouns are only autodetected if they end in -анин or -янин and are animate, to avoid many false positives. Other -ин nouns that follow this declension need an explicit declensional variant -ин. The noun is also animate, which needs to be noted.
<code><nowiki>{{ru-noun-table|боя́рин|-ин|a=an}}</nowiki></code>
produces
{{ru-noun-table|боя́рин|-ин|a=an}}
===Example 5: A noun needing a gender hint===
Nouns in -ь, e.g. {{m|ru|пло́щадь||square (open area in a city)}}, need a gender hint <code>m</code> or <code>f</code>, because the two genders correspond to different declensions and this can't be autodetected.
<code><nowiki>{{ru-noun-table|e|пло́щадь|f}}</nowiki></code>
produces
{{ru-noun-table|e|пло́щадь|f}}
===Example 6: A form needing an auto-accent override===
Unstressed suffixes need to be prefixed with <code>*</code> to indicate that they are unstressed; otherwise multisyllabic unstressed suffixes will trigger an error and monosyllabic unstressed suffixes will be auto-accented.
<code><nowiki>{{ru-noun-table|a|*-ник}}</nowiki></code>
produces
{{ru-noun-table|a|*-ник}}
===Example 7: A noun needing manual translit===
<code><nowiki>{{ru-noun-table|гетеросексуа́льность//getɛrosɛksuálʹnostʹ|f|n=sg}}</nowiki></code>
produces
{{ru-noun-table|гетеросексуа́льность//getɛrosɛksuálʹnostʹ|f|n=sg}}
==Examples with extra case forms==
===Example 1: An animate noun with a vocative case form===
The noun {{m|ru|де́ва||maiden}} has a special vocative де́во. This requires a case override; <code>~</code> can be used to stand for the stem де́в.
<code><nowiki>{{ru-noun-table|де́ва|voc=~о|a=an}}</nowiki></code>
produces
{{ru-noun-table|де́ва|voc=~о|a=an}}
===Example 2: A singular-only noun with a locative case===
The noun {{m|ru|пу́х||down (feathers)}} has a locative form пуху́. You can use the notation <code>+</code> to stand for the locative in the case override. Prepositions can optionally be supplied to indicate which prepositions can be used with the locative. The nouns is singular-only, which is indicated with {{para|n|sg}}. Because the noun is monosyllabic, an accent isn't needed and will automatically be supplied.
<code><nowiki>{{ru-noun-table|пух|loc=в +,на +|n=sg}}</nowiki></code>
produces
{{ru-noun-table|пух|loc=в +,на +|n=sg}}
==Reducible nouns, plural-only nouns, adjectival nouns==
===Example 1: A reducible noun===
The noun {{m|ru|па́лец||finger}} has the stem па́льц- in case forms other than the nominative singular. Such a noun is termed ''reducible''. This is specified using the <code>*</code> code.
<code><nowiki>{{ru-noun-table|па́лец|*}}</nowiki></code>
produces
{{ru-noun-table|па́лец|*}}
===Example 2: A reducible, plural-only (plurale tantum) noun===
The noun {{m|ru|воро́тца||wicket}} is not feminine but neuter, and occurs only in the plural. With a plural-only noun like this, the gender needs to be specified; the fact that the lemma is plural will then be recognized and the noun made plural-only. This noun is also reducible but in the other direction from па́лец: an extra vowel appears in the genitive plural (we term this ''dereducible''). This is again indicated with the <code>*</code> code.
<code><nowiki>{{ru-noun-table|воро́тца|n*}}</nowiki></code>
produces
{{ru-noun-table|воро́тца|n*}}
===Example 3: An adjectival noun===
The noun {{m|ru|уча́щийся||student}} is an ''adjectival noun'', i.e. a noun declined like an adjective, indicated with the code <code>+</code> (it is based on the present active participle of the verb {{m|ru|учи́ть||to learn, to teach}}). It has a reflexive suffix -ся added onto all forms, which is indicated with {{para|suffix|ся}}.
<code><nowiki>{{ru-noun-table|уча́щий|+|suffix=ся}}</nowiki></code>
produces
{{ru-noun-table|уча́щий|+|suffix=ся}}
==Nouns with е/ё alternation==
===Example 1===
{{m|ru|озерцо́||lake}} is accent pattern <code>d</code> and has unpredictable ё in the plural stem озёрц- (dereducible genitive plural озёрец). One way to indicate that is to use the code <code>;ё</code>, which indicates that the last -e- changes to -ё- when stressed.
<code><nowiki>{{ru-noun-table|d|озерцо́|*;ё}}</nowiki></code>
produces
{{ru-noun-table|d|озерцо́|*;ё}}
Another way is to distort the lemma by including the stressed form of the stem:
<code><nowiki>{{ru-noun-table|d|озёрце|*}}</nowiki></code>
or
<code><nowiki>{{ru-noun-table|d|озёрцо|*}}</nowiki></code>
The module will automatically generate nominative singular озерцо́ from the stem озёрц-; it knows that accent pattern <code>d</code> calls for ending stress in the nominative singular and that the unstressed equivalent of озёрц- is озерц-. Note also that the alternation between unstressed -це and stressed -цо́ is normal in Russian; the module will accept forms both ways, and convert to the <code>о</code> declension internally.
===Example 2===
{{m|ru|железа́||gland}} has complex stress alternation, as with {{m|ru|голова́||head}} above, but with the additional complication that ё appears in the genitive plural: nom sg железа́, nom pl же́лезы, gen pl желёз. The <code>;ё</code> code will take care of this.
<code><nowiki>{{ru-noun-table|f|железа́|;ё}}</nowiki></code>
produces
{{ru-noun-table|f|железа́|;ё}}
In this case, distorting the stem won't work; using же́леза results in incorrect gen pl желе́з, and using желёза results in incorrect nom pl желёзы.
==Nouns with irregular forms==
===Example 1: A noun with plural in irregular -а and partitive and locative case forms===
{{m|ru|снег||snow}}:
<code><nowiki>{{ru-noun-table|c|снег|(1)|par=+|loc=+}}</nowiki></code>
produces
{{ru-noun-table|c|снег|(1)|par=+|loc=+}}
===Example 2: A noun with irregularly stressed alternative nominative and genitive singular===
The noun {{m|ru|и́скра||spark}} has irregularly stressed forms in technical usage. Includes a usage note to this effect.
<code><nowiki>{{ru-noun-table|и́скра|nom_sg=и́скра,искра́*|gen_sg=и́скры,искры́*|notes=* Asterisk marks technical usage.}}</nowiki></code>
produces
{{ru-noun-table|и́скра|nom_sg=и́скра,искра́*|gen_sg=и́скры,искры́*|notes=* Asterisk marks technical usage.}}
===Example 3: A defective noun with a missing genitive plural===
A defective noun {{m|ru|хвала́||praise}} with a missing genitive plural.
<code><nowiki>{{ru-noun-table|хвала́|gen_pl=-}}</nowiki></code>
produces
{{ru-noun-table|хвала́|gen_pl=-}}
===Example 4: A noun with irregular plural stem and declensional variant -ья===
A noun {{m|ru|по́вод||rein}} with irregularly-stressed plural stem пово́д-, irregular plural ending in -ья, and a locative case form.
<code><nowiki>{{ru-noun-table|по́вод|-ья|пово́д|loc=+}}</nowiki></code>
produces
{{ru-noun-table|по́вод|-ья|пово́д|loc=+}}
===Example 5: An animate noun needing declensional variant -ище===
The noun {{m|ru|волчи́ще||large or mature wolf}} (an [[augmentative]]) needs the declensional variant <code>-ище</code> due to its declension, which includes alternative colloquial singular case forms with feminine endings. Nouns in this class are masculine, animate and special case <code>(1)</code> (i.e. they have the nominative plural in -и instead of -а), and at least the latter two properties must also be specified or an error occurs.
<code><nowiki>{{ru-noun-table|волчи́ще|m-ище(1)|a=an}}</nowiki></code>
produces
{{ru-noun-table|волчи́ще|m-ище(1)|a=an}}
==Nouns with multiple and/or mixed declensions==
===Example 1: Multiple stress patterns===
The noun {{m|ru|мост||bridge}} has multiple stress patterns in the singular, except for the prepositional singular (as well as a locative case form). Implemented by placing it in two stress classes and overriding the prepositional singular. Note that when two forms from different stress patterns coincide, only one form is shown. The word is monosyllabic and doesn't need an accent mark, which will automatically be placed (but it wouldn't cause problems if the accent were added).
<code><nowiki>{{ru-noun-table|b,c|мост|pre_sg=мо́сте|loc=+}}</nowiki></code>
produces
{{ru-noun-table|b,c|мост|pre_sg=мо́сте|loc=+}}
===Example 2: Multiple stems===
{{m|ru|фено́мен||phenomenon}}, also stressed as {{m|ru|феноме́н}}:
<code><nowiki>{{ru-noun-table|феноме́н|or|фено́мен}}</nowiki></code>
produces
{{ru-noun-table|феноме́н|or|фено́мен}}
===Example 3: Multiple plurals===
{{m|ru|лоску́т||rag, scrap}} has two plurals from different declension classes and different stress patterns: лоску́ты and лоскутья́.
<code><nowiki>{{ru-noun-table|лоску́т|or|d||-ья}}</nowiki></code>
produces
{{ru-noun-table|лоску́т|or|d||-ья}}
===Example 4: Multiple plurals===
{{m|ru|мальчо́нок||little boy}} also has two plurals: мальчо́нки (hard-consonant declension) and мальча́та (<code>ёнок</code> declension).
<code><nowiki>{{ru-noun-table|мальчо́нок|#*|or|a=an}}</nowiki></code>
produces
{{ru-noun-table|мальчо́нок|#*|or|a=an}}
Note the use of <code>#</code> to explicitly indicate the hard-consonant declension; without this, the lemma would be autodetected as belonging to the <code>ёнок</code> declension. Note also that in the second argument set, all arguments have been defaulted, with the lemma defaulting to the same as in the first argument set.
===Example 5: Multiple plurals===
{{m|ru|сапожо́к||boot}} has two plurals: сапо́жки (pattern <code>d</code>) and сапожки́ (pattern <code>b</code>). They cannot be combined into a stress pattern <code>d,b</code> because the former also has irregular endingless genitive plural сапо́жек, indicated by code <code>(2)</code>.
<code><nowiki>{{ru-noun-table|d|сапожо́к|*(2)|or|b||*}}</nowiki></code>
produces
{{ru-noun-table|d|сапожо́к|*(2)|or|b||*}}
===Example 6: Mixed declensions===
{{m|ru|коле́но}} has three possible plurals depending on its meaning: a normal one in -а in the meaning "bend, generation, tribe"; an unusual one in -и (looking like the plural of masculine ь-m class) in the meaning "knee"; and one in -ья in the meaning "joint". These unusual plural can be expressed as a mixed declension:
* <code><nowiki>{{ru-noun-table|коле́н|о/ь-m}}</nowiki></code> (knee)
* <code><nowiki>{{ru-noun-table|коле́но}}</nowiki></code> (bend, generation, tribe)
* <code><nowiki>{{ru-noun-table|коле́но|-ья}}</nowiki></code> (joint)
produces
{{ru-noun-table|коле́н|о/ь-m}}
{{ru-noun-table|коле́но}}
{{ru-noun-table|коле́но|-ья}}
===Example 7: Multiple stems and mixed declensions===
{{m|ru|ка́мень||stone}}:
<code><nowiki>{{ru-noun-table|ка́мень|*m|or||*m-ья|каме́н|pltail=*|notes=* ''The plurals marked with an asterisk are antiquated forms.''}}</nowiki></code>
produces
{{ru-noun-table|ка́мень|*m|or||*m-ья|каме́н|pltail=*|notes=* ''The plurals marked with an asterisk are antiquated forms.''}}
Note the use of a plural stem in the second set of plural forms, the use of the masculine-gender hint, the plural variant <code>-ья</code> for these forms, and the use of {{para|pltail}} to add an asterisk to these forms, with a note indicating that they are antiquated.
===Example 8: Multiple stems and mixed declensions, with plural suppletion===
{{m|ru|ребёнок||child}} is a particularly complex case. It follows the <code>ёнок</code> declension (singular -ёнок, -ёнка; plural -я́та, -я́т), with two plurals, an expected secondary one ребя́та and an unexpected primary one де́ти with a completely different stem and declension. This form де́ти looks somewhat like the plural of an accent-class <code>e</code> or <code>f</code> noun of the <code>ь-m</code> declension (masculine soft-stem), but with further irregularities. The secondary plural tends to have a different meaning. To indicate all this, we use a mixed declension with a special plural stem to handle the primary plural, overrides to handle the irregularities, and {{para|pltail}} with {{para|notes}} to indicate the different meaning of the secondary plural. We choose accent class <code>f</code> in the primary plural so that the singular ending -ёнок gets the stress.
<code><nowiki>{{ru-noun-table|f|реб|ёнок/ь-m|дет|or|ребёнок|dat_pl=де́тям,ребя́там*|ins_pl=детьми́,ребя́тами*|pre_pl=де́тях,ребя́тах*|a=an|pltail=*|notes=* Use the second plural with the meaning "boys!", "fellows!", "guys!", "comrades!".}}</nowiki></code>
produces
{{ru-noun-table|f|реб|ёнок/ь-m|дет|or|ребёнок|dat_pl=де́тям,ребя́там*|ins_pl=детьми́,ребя́тами*|pre_pl=де́тях,ребя́тах*|a=an|pltail=*|notes=* Use the second plural with the meaning "boys!", "fellows!", "guys!", "comrades!".}}
==Multi-word nouns==
===Example 1: An adjective-noun combination===
For the noun {{m|ru|мя́гкий зна́к||soft sign}}:
<code><nowiki>{{ru-noun-table|мя́гкий|+|_|знак}}</nowiki></code>
produces
{{ru-noun-table|мя́гкий|+|_|знак}}
Note how both parts are declined appropriately.
Links can be placed around the individual words, and the words will appear linked in the declension table title. This is especially useful in {{temp|ru-noun+}}, where the links will appear in the headword. For example, the above could be written as follows:
<code><nowiki>{{ru-noun-table|[[мя́гкий]]|+|_|[[зна́к]]}}</nowiki></code>
which produces
{{ru-noun-table|[[мя́гкий]]|+|_|[[зна́к]]}}
Note that the accent marks in the links will appear in the anchor text of the link but will be correctly stripped in the page linked to (since Wiktionary Russian-language page names don't have acute accents in them). Note also that знак as an argument by itself (not surrounded by a link) will be auto-accented since it's monosyllabic and not preceded by a <code>*</code> (which suppresses auto-accenting), but this doesn't (currently) happen with links; hence we've added the accent ourselves.
===Example 2: A noun-noun combination separated by a hyphen===
For the noun {{m|ru|пау́к-во́лк||wolf spider}}:
<code><nowiki>{{ru-noun-table|b|пау́к|-|e|волк|a=an}}</nowiki></code>
produces
{{ru-noun-table|b|пау́к|-|e|волк|a=an}}
Note that the animacy applies to the entire expression.
The linked version would be
<code><nowiki>{{ru-noun-table|b|[[пау́к]]|-|e|[[во́лк]]|a=an}}</nowiki></code>
which produces
{{ru-noun-table|b|[[пау́к]]|-|e|[[во́лк]]|a=an}}
===Example 3: A noun with a genitive modifier===
For the noun {{m|ru|ору́жие ма́ссового уничтоже́ния||weapon of mass destruction}}:
<code><nowiki>{{ru-noun-table|ору́жие|_|ма́ссового|$|_|уничтоже́ния|$}}</nowiki></code>
produces
{{ru-noun-table|ору́жие|_|ма́ссового|$|_|уничтоже́ния|$}}
Note the use of <code>$</code> to indicate indeclinable words. Formerly, <code>+$</code> was necessary to indicate adjectival indeclinable words (i.e. words where final -го should be transliterated -vo), but this is now handled automatically.
The version with links would appear as follows:
<code><nowiki>{{ru-noun-table|[[ору́жие]]|_|[[массовый|ма́ссового]]|$|_|[[уничтожение|уничтоже́ния]]|$}}</nowiki></code>
which produces
{{ru-noun-table|[[ору́жие]]|_|[[массовый|ма́ссового]]|$|_|[[уничтожение|уничтоже́ния]]|$}}
===Example 4: A noun with a prepositional phrase modifier===
For the noun {{m|ru|кре́м для ру́к||hand cream}}:
<code><nowiki>{{ru-noun-table|крем|_|*для|$|_|рук|$}}</nowiki></code>
produces
{{ru-noun-table|крем|_|*для|$|_|рук|$}}
Note the use of <code>*</code> at the beginning of для to suppress the stress mark that otherwise would automatically be added.
The linked version would be
<code><nowiki>{{ru-noun-table|[[кре́м]]|_|*[[для]]|$|_|[[рука|ру́к]]|$}}</nowiki></code>
which produces
{{ru-noun-table|[[кре́м]]|_|*[[для]]|$|_|[[рука|ру́к]]|$}}
Note that the <code>*</code> that suppresses auto-adding of the stress mark is technically not required since auto-adding stress doesn't currently happen inside links, but it's a good idea anyway because auto-stressing in links may be implemented in the future.
===Example 5: A noun that combines singular and plural components (and requires manual translit)===
For the noun {{m|ru|Сент-Ви́нсент и Гренади́ны||Saint Vincent and the Grenadines|tr=Sɛnt-Vínsɛnt i Grenadíny}}:
<code><nowiki>{{ru-noun-table|Сент-Ви́нсент//Sɛnt-Vínsɛnt|_|*и|$|_|Гренади́ны|m(2)|n1=s|n=p}}</nowiki></code>
produces
{{ru-noun-table|Сент-Ви́нсент//Sɛnt-Vínsɛnt|_|*и|$|_|Гренади́ны|m(2)|n1=s|n=p}}
The whole expression is plural, as is the word Гренади́ны, but Сент-Ви́нсент is declined in the singular. This is specified using the per-word parameter {{para|n1|s}}, specifying that the first word should be declined as singular. As in the previous example, <code>*</code> is prepended to и to suppress the automatic addition of a stress mark. Гренади́ны is masculine but uses the alternative no-ending genitive plural; hence the use of special case <code>(2)</code>.
===Example 6: A particularly long noun===
For the noun {{m|ru|носово́й радиопрозра́чный обтека́тель анте́нны радиолокацио́нной ста́нции||dielectric plastic nose cap|tr=nosovój radioprozráčnyj obtekátelʹ antɛ́nny radiolokaciónnoj stáncii}}:
<code><nowiki>{{ru-noun-table|[[носово́й]]|+|_|[[радиопрозра́чный]]|+|_|[[обтека́тель]]|m|_|[[антенна|анте́нны]]//antɛ́nny|$|_|[[радиолокационный|радиолокацио́нной]]|$|_|[[станция|ста́нции]]|$}}</nowiki></code>
produces
{{ru-noun-table|[[носово́й]]|+|_|[[радиопрозра́чный]]|+|_|[[обтека́тель]]|m|_|[[антенна|анте́нны]]//antɛ́nny|$|_|[[радиолокационный|радиолокацио́нной]]|$|_|[[станция|ста́нции]]|$}}
Note that there is no limit to the number of components in a noun.
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်]]
</includeonly>
54fibm45yibmepais84atmlc9zl8vd3
ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်
14
297514
399791
2026-07-21T01:54:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]"
399791
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]
4la63dbdrxq324cxhjywjgrpqptt1ol
ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
297515
399792
2026-07-21T01:56:13Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]"
399792
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]
s55qfiz1u4c13j84aapyretrr90iibw
မဝ်ဂျူ:ru-noun/documentation
828
297516
399794
2026-07-21T02:41:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module implements {{temp|ru-noun-table}}, as well as {{temp|ru-generate-noun-forms}} and {{temp|ru-generate-noun-args}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]]. <includeonly> {{module cat|ru}} </includeonly>"
399794
wikitext
text/x-wiki
This module implements {{temp|ru-noun-table}}, as well as {{temp|ru-generate-noun-forms}} and {{temp|ru-generate-noun-args}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]].
<includeonly>
{{module cat|ru}}
</includeonly>
7l8o2y145a2a45161fm0i0sh5dedjdg
399795
399794
2026-07-21T02:42:32Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:ru-noun/doc]] ဇရေင် [[မဝ်ဂျူ:ru-noun/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399794
wikitext
text/x-wiki
This module implements {{temp|ru-noun-table}}, as well as {{temp|ru-generate-noun-forms}} and {{temp|ru-generate-noun-args}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]].
<includeonly>
{{module cat|ru}}
</includeonly>
7l8o2y145a2a45161fm0i0sh5dedjdg
ကဏ္ဍ:မဝ်ဂျူရုဿျှာဂမၠိုၚ်
14
297517
399796
2026-07-21T02:44:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာရုဿျှာ|ရုဿျှာ]] » '''မဝ်ဂျူဂမ..."
399796
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာရုဿျှာ|ရုဿျှာ]] » '''မဝ်ဂျူဂမၠိုၚ်'''
:[[:ကဏ္ဍ:မဝ်ဂျူဂမၠိုၚ်|မဝ်ဂျူ]]ဘာသာရုဿျှာ၊ မနွံကဵုလုပ်အဝေါၚ်ကုဒ် Lua နကဵုမကၠောန်ဗဒှ် ကဵု မစဳရေၚ်ယဵုဒုၚ်သ္ပမာန်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာရုဿျှာ]][[ကဏ္ဍ:မဝ်ဂျူဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]
mdslqtszjpby6zu00irpy7ozqtjmvso
ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲရုဿျှာဂမၠိုၚ်
14
297518
399797
2026-07-21T02:46:11Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူရုဿျှာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]"
399797
wikitext
text/x-wiki
[[ကဏ္ဍ:မဝ်ဂျူရုဿျှာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]
gcin15035ioc8l1svnm0oy0qwyxt4up
ထာမ်ပလိက်:sh-decl-noun-unc
10
297519
399802
2026-07-21T03:20:16Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|warn}}<!-- Validate template parameters --><div class="NavFrame" style="{{#ifeq: {{{style|}}}|right|float:right; clear:right;|}}max-width:{{{width|30}}}em"> <div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);" >{{#if:{{{title|}}}|{{{title}}}|{{#if:{{NAMESPACE}}||မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m-self|sh|{{pagename}}}}}}}}</div> <div clas..."
399802
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
--><div class="NavFrame" style="{{#ifeq: {{{style|}}}|right|float:right; clear:right;|}}max-width:{{{width|30}}}em">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);" >{{#if:{{{title|}}}|{{{title}}}|{{#if:{{NAMESPACE}}||မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m-self|sh|{{pagename}}}}}}}}</div>
<div class="NavContent">
{| style="width:{{{width|30}}}em;" class="inflection-table inflection"
|- class="rowgroup"
! style="background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {{{pltitle|singular}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''မဒုၚ်ယၟု'''
| {{l-self|sh|{{{ns|{{{1|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ဗဳဇဂကူ'''
| {{l-self|sh|{{{gs|{{{2|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပြကမ္မကာရက'''
| {{l-self|sh|{{{ds|{{{3|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ကမ္မကာရက'''
| {{l-self|sh|{{{as|{{{4|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပရေၚ်ဂယိုၚ်လမျီု'''
| {{l-self|sh|{{{vs|{{{5|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ခၞံဗဒှ်ဌာန်မတန်တဴ'''
| {{l-self|sh|{{{ls|{{{6|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်'''
| {{l-self|sh|{{{is|{{{7|—}}}}}}}}
|}</div></div><noinclude>{{tcat|ndecl:*}}</noinclude>
7c07380bkpivbi8cx8zv5wl4wfzo71j
399803
399802
2026-07-21T03:20:50Z
咽頭べさ
33
399803
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
--><div class="NavFrame" style="{{#ifeq: {{{style|}}}|right|float:right; clear:right;|}}max-width:{{{width|30}}}em">
<div class="NavHead" style="background:var(--wikt-palette-lighterblue, #ebf4ff);" >{{#if:{{{title|}}}|{{{title}}}|{{#if:{{NAMESPACE}}||မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m-self|sh|{{pagename}}}}}}}}</div>
<div class="NavContent">
{| style="width:{{{width|30}}}em;" class="inflection-table inflection"
|- class="rowgroup"
! style="background:var(--wikt-palette-lightblue, #d9ebff);" |
! style="background:var(--wikt-palette-lightblue, #d9ebff);" | {{{pltitle|ကိုန်ဨကဝုစ်}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''မဒုၚ်ယၟု'''
| {{l-self|sh|{{{ns|{{{1|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ဗဳဇဂကူ'''
| {{l-self|sh|{{{gs|{{{2|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပြကမ္မကာရက'''
| {{l-self|sh|{{{ds|{{{3|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ကမ္မကာရက'''
| {{l-self|sh|{{{as|{{{4|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပရေၚ်ဂယိုၚ်လမျီု'''
| {{l-self|sh|{{{vs|{{{5|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ခၞံဗဒှ်ဌာန်မတန်တဴ'''
| {{l-self|sh|{{{ls|{{{6|—}}}}}}}}
|-
! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်'''
| {{l-self|sh|{{{is|{{{7|—}}}}}}}}
|}</div></div><noinclude>{{tcat|ndecl:*}}</noinclude>
7ob4ybfowgl065f5md92gxhp845951z
ထာမ်ပလိက်:uk-ndecl
10
297520
399804
2026-07-21T03:22:20Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:uk-noun|show}}<!-- --><noinclude>{{documentation}}</noinclude>"
399804
wikitext
text/x-wiki
{{#invoke:uk-noun|show}}<!--
--><noinclude>{{documentation}}</noinclude>
t612hybxb2fvv16s501kl4kjt60il23
မဝ်ဂျူ:uk-noun/documentation
828
297521
399806
2026-07-21T04:08:05Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module supports {{temp|uk-ndecl}} and {{temp|uk-ndecl-manual}}, {{temp|uk-ndecl-manual-sg}} and {{temp|uk-ndecl-manual-pl}}. ==Functions== {{module documentation}} <includeonly> {{module cat|uk}} </includeonly>"
399806
wikitext
text/x-wiki
This module supports {{temp|uk-ndecl}} and {{temp|uk-ndecl-manual}}, {{temp|uk-ndecl-manual-sg}} and {{temp|uk-ndecl-manual-pl}}.
==Functions==
{{module documentation}}
<includeonly>
{{module cat|uk}}
</includeonly>
6vqbm2gz1yn7hc9dce0dv1l96gydkxi
399807
399806
2026-07-21T04:08:39Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:uk-noun/doc]] ဇရေင် [[မဝ်ဂျူ:uk-noun/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399806
wikitext
text/x-wiki
This module supports {{temp|uk-ndecl}} and {{temp|uk-ndecl-manual}}, {{temp|uk-ndecl-manual-sg}} and {{temp|uk-ndecl-manual-pl}}.
==Functions==
{{module documentation}}
<includeonly>
{{module cat|uk}}
</includeonly>
6vqbm2gz1yn7hc9dce0dv1l96gydkxi
ကဏ္ဍ:မဝ်ဂျူယူကရိန်ဂမၠိုၚ်
14
297522
399808
2026-07-21T04:45:05Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာယူကရိန်|ယူကရိန်]] » '''မဝ်ဂျူ..."
399808
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာယူကရိန်|ယူကရိန်]] » '''မဝ်ဂျူဂမၠိုၚ်'''
:[[:ကဏ္ဍ:မဝ်ဂျူဂမၠိုၚ်|မဝ်ဂျူ]]ဘာသာယူကရိန်၊ မနွံကဵုလုပ်အဝေါၚ်ကုဒ် Lua နကဵုမကၠောန်ဗဒှ် ကဵု မစဳရေၚ်ယဵုဒုၚ်သ္ပမာန်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာယူကရိန်]][[ကဏ္ဍ:မဝ်ဂျူဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]
igxj2rrfr2glqfsfrluzxsbqna35rln
ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲယူကရိန်ဂမၠိုၚ်
14
297523
399809
2026-07-21T05:58:30Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူယူကရိန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]"
399809
wikitext
text/x-wiki
[[ကဏ္ဍ:မဝ်ဂျူယူကရိန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]
bwle9fj5zc7yga5bnyiokm668rw4cui
ထာမ်ပလိက်:uk-ndecl/documentation
10
297524
399810
2026-07-21T06:01:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|Module:uk-noun}} ==Parameters== Normally there is only one parameter to specify, e.g. for {{m|uk|бана́н||banana}}: :{{temp|uk-ndecl|бана́н<>}} which produces {{uk-ndecl|бана́н<>}} Note that the lemma is given followed by angle brackets, and an accent needs to be placed on the appropriate syllable (it can be omitted in monosyllabic words). In some cases, proper..."
399810
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:uk-noun}}
==Parameters==
Normally there is only one parameter to specify, e.g. for {{m|uk|бана́н||banana}}:
:{{temp|uk-ndecl|бана́н<>}}
which produces
{{uk-ndecl|бана́н<>}}
Note that the lemma is given followed by angle brackets, and an accent needs to be placed on the appropriate syllable (it can be omitted in monosyllabic words). In some cases, properties need to be given inside of angle brackets, for example for {{m|uk|стари́к||old man}}:
:{{temp|uk-ndecl|стари́к<b.pr>}}
which produces
{{uk-ndecl|стари́к<b.pr>}}
Here, we specify two properties: <code>b</code> (a stress pattern indicator, in this case specifying that the noun is end-stressed, i.e. the stress is on the endings rather than the stem) and <code>pr</code> (indicating that this is a ''personal'' noun, where the accusative is the same as the genitive rather than the nominative).
The general format is the accented noun lemma (the nominative singular, or nominative plural for plural-only nouns), followed by a spec in angle brackets. The format of the spec is
:<code><PROP.PROP.PROP...></code>
i.e. one or more properties, separated by periods. All properties are optional.
The following properties are recognized:
* Gender: <code>M</code> for masculine, <code>F</code> for feminine, <code>MF</code> for nouns that can be either masculine or feminine, <code>N</code> for neuter. Most of the time this isn't needed, but it's required for certain nouns (e.g. most nouns ending in ''-ь'' and some nouns ending in ''-я'') to determine the correct declension type. Note that the gender must be given capitalized.
* Stress pattern: <code>a</code>, <code>b</code>, <code>c</code>, <code>d</code>, <code>d'</code>, <code>e</code>, <code>f</code> or <code>f'</code>. These are based on Zaliznyak's Russian-language patterns. Multiple comma-separated stress patterns can be given. See below for more information.
* Reducibility: <code>*</code> to indicate an alternation between a vowel (one of ''о'', ''е'', ''є'' or occasionally ''і'') and no vowel in the final syllable, where the vowel appears in endings that do not themselves contain a vowel (typically the nominative/accusative singular and/or the genitive plural). This code should be placed directly after or used in place of the stress pattern, e.g. <code>c*</code> to indicate a reducible noun with stress pattern ''c'', <code>b*,b</code> to indicate a noun with stress pattern ''b'' that can be either reducible or non-reducible, and just <code>*</code> to indicate a reducible noun with the default stress pattern.
* Reversed genitive plural stress: <code>#</code> to indicate that the genitive plural stress is the opposite of what the stress pattern calls for. This code should be placed directly after or used in place of the stress pattern, e.g. <code>c#</code> to indicate a noun with stress pattern ''c'' and reversed genitive plural stress, <code>c*#</code> to indicate a reducible noun with stress pattern ''c'' and reversed genitive plural stress, <code>d#,d</code> to indicate a noun with stress pattern ''d'' that can have either reversed or normal genitive plural stress, and just <code>#</code> to indicate a noun with reversed genitive plural stress and the default stress pattern.
* Animacy: <code>pr</code> for personal nouns, <code>anml</code> for animal nouns, <code>inan</code> for inanimate nouns. The default is almost always inanimate (except when <code>t</code> or <code>surname</code> are specified); animate nouns need an animacy code given.
* Number: <code>sg</code> for singular-only nouns, <code>pl</code> for plural-only nouns. If unspecified, nouns have both singular and plural.
* Softness/hardness:
** <code>soft</code> to indicate soft endings for a noun ending in Cyrillic ''-р'';
** <code>semisoft</code> to indicate semisoft endings for a noun ending in Cyrillic ''-р'';
** <code>plsoft</code> to indicate soft plural endings, e.g. for {{m|uk|друг||friend}} (only works currently for masculine and feminine hard-stem nouns);
** <code>plhard</code> to indicate hard plural endings, e.g. for {{m|uk|ім'я́||name}} (only works currently for neuters in ''-я'').
* Vowel alternations:
** <code>i</code> (a Latin-script ''i'', not a Cyrillic script ''i'') to indicate a change from Cyrillic ''о'' or ''е'' to ''і'' when the ending does not begin with a vowel;
** <code>io</code> (a Latin-script ''io'') to indicate a change from ''і'' to ''о'' when the ending ''does'' begin with a vowel;
** <code>ie</code> (a Latin-script ''ie'') to indicate a similar change from ''і'' to ''е'' when the ending begins with a vowel.
* Special variants:
** <code>in</code> to indicate that a noun ending in ''-ин'' (e.g. {{m|uk|кия́нин||Kyivan}}, {{m|uk|християни́н||Christian}}) loses this ending in the plural;
** <code>3rd</code> to indicate that a soft feminine plural-only noun is third-declension rather than first-declension (i.e. its singular would end in ''-ь'' or a consonant rather than ''-я'' or ''-а'');
** <code>surname</code> to indicate that the noun is a surname, in which case the vocative singular can be the same as the nominative singular in addition to its normal form (this implies <code>pr</code>, as surnames normally refer to people);
** <code>t</code> to indicate ''t''-stem neuter nouns, i.e. that a neuter noun ending in ''-я'' (e.g. {{m|uk|ягня́||lamb}}) has a stem ''-ят'' in most forms (this implies <code>anml</code>, as nouns of this form usually refer to the young of animals);
** <code>en</code> to indicate ''en''-stem neuter nouns, i.e. that a neuter noun ending in ''-м'я'' has alternative forms utilizing a stem in ''-ен'' in most singular forms (e.g. {{m|uk|ви́м'я||udder}} with alternative genitive/dative/locative singular ''ви́мені'' and alternative instrumental singular ''ви́менем'').
* Stem overrides:
** <code>stem:STEM</code> to specify a different stem than the lemma's stem to use for endings beginning with a vowel;
** <code>plstem:STEM</code> to specify a different stem to use in the plural.
* Specific form overrides: Examples are <code>genu</code> to specify that the genitive singular ends in ''-у'', <code>locju:i</code> to specify that the locative singular ends in ''-ю'' or ''-і'', <code>vóce</code> to specify that the vocative singular ends in ''-е'' with stress on the stem (regardless of the accent pattern) and <code>genpl:земе́ль</code> to specify that the genitive plural has the value ''земе́ль''. These are explained more below.
The properties can be given in any order, but it is recommended that the following order be used:
# Gender
# Stress pattern, reducibility, reversed genitive plural stress
# Adjectival indicator
# Animacy
# Number
# Softness/hardness
# Vowel alternations
# Special variants
# Stem overrides
# Specific form overrides
==Gender==
The gender can be specified using <code>M</code> for masculine, <code>F</code> for feminine, <code>MF</code> for nouns that can be either masculine or feminine, and <code>N</code> for neuter. The gender can usually be omitted, but is required in certain cases, e.g. with some nouns ending in ''-ь'' and some nouns ending in ''-я''. If the gender is omitted, it defaults as follows:
# Nouns ending in a consonant default to masculine.
# Nouns ending in a soft sign must have the gender explicitly given, except in the following cases:
## Nouns ending in ''-ець'' and ''-єць'', stressed or unstressed, default to masculine.
## Nouns ending in unstressed ''-тель'' default to masculine.
## Nouns ending in unstressed ''-ість'' default to feminine.
# Nouns ending in ''-а'' default to feminine.
# Nouns ending in ''-о'' or ''-е'' default to neuter.
# Nouns ending in ''-'я'' (e.g. {{m|uk|здоро́в'я||health}}, {{m|uk|переми́р'я||ceasefire}}, {{m|uk|ті́м'я||crown (of the head)}}) or in a double consonant + ''-я'' (e.g. {{m|uk|зна́чення||importance; meaning}}, {{m|uk|обли́ччя||face; character}}, {{m|uk|життя́||life}}) default to neuter.
# Nouns with the code <code>t</code> (e.g. {{m|uk|ягня́||lamb}}, {{m|uk|порося́||piglet}}) default to neuter.
# Other nouns in ''-я'' default to feminine.
The gender needs to be explicitly given in the following cases:
# Nouns ending in a soft sign other than those mentioned above; e.g. {{m|uk|готе́ль||hotel}} (masculine), {{m|uk|моде́ль||model}} (feminine).
# Masculine or feminine nouns ending in ''-'я'' (e.g. {{m|uk|сім'я́||family}}, which is feminine) or in a double consonant + ''-я'' (e.g. {{m|uk|стаття́||article}}, which is feminine, and {{m|uk|суддя́||judge}}, which is either masculine or feminine).
# Feminine nouns ending in a consonant; e.g. {{m|uk|любо́в||love}}, {{m|uk|ніч||night}}.
# Neuter nouns ending in ''-я'' other than the two types mentioned above; e.g. {{m|uk|зап'я́стя||wrist}}, {{m|uk|пові́тря||air}}.
Examples:
1. {{m|uk|автомобі́ль||car}} (masculine) ends in a soft sign, and so needs the gender to be specified:
{{demo|<nowiki>{{uk-ndecl|автомобі́ль<M>}}</nowiki>}}
2. {{m|uk|любо́в||love}} is feminine and ends in a consonant, and so needs the gender to be specified:
{{demo|<nowiki>{{uk-ndecl|любо́в<F.sg>}}</nowiki>}}
3. {{m|uk|зап'я́стя||wrist}} is neuter but does not end in a double consonant + ''-я'', and so needs the gender to be specified:
{{demo|<nowiki>{{uk-ndecl|зап'я́стя<N>}}</nowiki>}}
4. {{m|uk|мужчи́на||man}} is masculine but ends in ''-а'', which defaults to feminine. In this case, masculine and feminine nouns in ''-а'' have identical declensions, so the gender doesn't need to be given, but it's a good idea to specify it anyway, because it is needed in {{temp|uk-noun}} (when it is modified to support syntax similar to {{temp|uk-ndecl}}, parallel to {{temp|ru-noun+}}).
{{demo|<nowiki>{{uk-ndecl|мужчи́на<M.pr>}}</nowiki>}}
==Stress patterns and reducibility==
The following table specifies where the stress falls (stem or ending):
{| class="wikitable"
!
! colspan="20" style="text-align: center; font-weight:bold;" | The Stress Falls on:
|-
| style="font-weight:bold;" | Pattern Letter
| colspan="2" style="text-align: center; font-weight:bold;" | a
| colspan="2" style="text-align: center; font-weight:bold;" | b
| colspan="2" style="text-align: center; font-weight:bold;" | c
| colspan="2" style="text-align: center; font-weight:bold;" | d
| colspan="2" style="text-align: center; font-weight:bold;" | d'
| colspan="2" style="text-align: center; font-weight:bold;" | e
| colspan="2" style="text-align: center; font-weight:bold;" | f
| colspan="2" style="text-align: center; font-weight:bold;" | f'
|-
| style="font-weight:bold;" | Number
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
| style="text-align: center; font-weight:bold;" | sg
| style="text-align: center; font-weight:bold;" | pl
|-
| style="font-weight:bold;" | Nom
| stem
| stem
| ending
| ending
| stem
| ending
| ending
| stem
| ending
| stem
| stem
| '''stem'''
| ending
| '''stem'''
| ending
| '''stem'''
|-
| style="font-weight:bold;" | Acc
| stem
|
| ending
|
| stem
|
| ending
|
| '''stem'''
|
| stem
|
| ending
|
| '''stem'''
|
|-
| style="font-weight:bold;" | Gen
| stem
| stem
| ending
| ending
| stem
| ending
| ending
| stem
| ending
| stem
| stem
| ending
| ending
| ending
| ending
| ending
|-
| style="font-weight:bold;" | Dat
| stem
| stem
| ending
| ending
| stem
| ending
| ending
| stem
| ending
| stem
| stem
| ending
| ending
| ending
| ending
| ending
|-
| style="font-weight:bold;" | Ins
| stem
| stem
| ending
| ending
| stem
| ending
| ending
| stem
| ending
| stem
| stem
| ending
| ending
| ending
| ending
| ending
|-
| style="font-weight:bold;" | Loc
| stem
| stem
| ending
| ending
| stem
| ending
| ending
| stem
| ending
| stem
| stem
| ending
| ending
| ending
| ending
| ending
|-
| style="font-weight:bold;" | Voc
|
| stem
|
| ending
|
| ending
|
| stem
|
| stem
|
| '''stem'''
|
| '''stem'''
|
| '''stem'''
|-
| style="font-weight:bold;" | Example
| colspan="2" style="text-align: center;" | {{m|uk|бана́н}}
| colspan="2" style="text-align: center;" | {{m|uk|лист}}
| colspan="2" style="text-align: center;" | {{m|uk|чорт}}
| colspan="2" style="text-align: center;" | {{m|uk|число́}}
| colspan="2" style="text-align: center;" | {{m|uk|вода́}}
| colspan="2" style="text-align: center;" | {{m|uk|смерть}}
| colspan="2" style="text-align: center;" | {{m|uk|щока́}}
| colspan="2" style="text-align: center;" | {{m|uk|рука́}}
|}
<br>
'''NOTE''': Boldfaced cases differ from the other cases in the same number (singular or plural).
The accusative plural is left out in the above table because it is derived from either the nominative plural, genitive plural or both, depending on the noun's animacy. The vocative singular is left out because it is frequently stem-stressed even when the remaining singular cases are ending-stressed. (Whether or not this special case applies depends on the particular declension and sometimes other factors.)
An example needing the stress pattern specified is {{m|uk|каву́н||watermelon}}, with stress pattern b (genitive singular ''кавуна́'', nominative plural ''кавуни́'', etc.):
:{{temp|uk-ndecl|каву́н<b>}}
which produces
{{uk-ndecl|каву́н<b>}}
Some nouns are ''reducible'', meaning they have an alternation between a vowel (''о'', ''е'', ''є'' or occasionally ''і'') before the final consonant in forms where the ending does ''not'' begin with a vowel, and no vowel in forms where the ending does begin with a vowel. The forms that use the unreduced stem variant are the nominative singular of masculine nouns; the accusative singular of inanimate masculine nouns; the genitive plural of feminine nouns in ''-а'' and ''-я'', and of neuter nouns in general; and (theoretically) the nominative, accusative and instrumental singular of third-declension feminine nouns. All other forms use the reduced stem variant.
An example is {{m|uk|све́кор||wife's father-in-law}}, where most forms use a stem ''свекр-'' (genitive singular ''све́кра'', nominative plural ''све́кри'', etc.):
:{{temp|uk-ndecl|све́кор<*.pr>}}
which produces
{{uk-ndecl|све́кор<*.pr>}}
If both a stress pattern and the reducible indicator need to be given, they should be combined, as with {{m|uk|за́єць||hare}} (reduced stem ''зайц-'', genitive singular ''за́йця'', nominative plural ''зайці́'', etc.):
:{{temp|uk-ndecl|за́єць<c*.anml>}}
which produces
{{uk-ndecl|за́єць<c*.anml>}}
Multiple stress patterns can be given, comma-separated. An example needing this is {{m|uk|горі́лка||vodka}}, with nominative plural either ''горі́лки'' (stem-stressed) or ''горілки́'' (ending-stressed):
:{{temp|uk-ndecl|горі́лка<a*,c*>}}
which produces
{{uk-ndecl|горі́лка<a*,c*>}}
This noun is reducible because the genitive plural is ''горі́лок'' or ''горіло́к''.
The default stress pattern is as follows:
* The default is <code>b</code> in the following cases:
*# The lemma is plural-only and ends in a stressed vowel (e.g. {{m|uk|вуста́||mouth, lips}}).
*# The lemma is masculine and ends in stressed ''-о́'' or ''-е́'' (e.g. {{m|uk|Петро́||Peter}}).
*# The lemma is neuter and ends in stressed ''-я́'' or ''-а́'' (e.g. {{m|uk|здання́||opinion}}, {{m|uk|порося́||piglet}}, {{m|uk|лоша́||foal}}, {{m|uk|ім'я́||name}}).
*# The lemma is reducible and the stress is on the reducible vowel (e.g. {{m|uk|замо́к||lock}}, {{m|uk|стіле́ць||pencil}}).
* Otherwise, if the lemma ends in a stressed vowel (which includes all feminines, and all neuters in ''-о́'' and ''-е́''), the default is <code>d</code>.
* Otherwise, the default is <code>a</code>.
==Reversed genitive plural stress==
Several nouns have unexpected stress in the genitive plural. This could be controlled using an override, but because of its commonness, a shortcut is available using the code <code>#</code>. This code should be placed directly after the stress pattern, as with the reducible code <code>*</code>. If both <code>*</code> and <code>#</code> need to be given, either order is possible, but by convention the order <code>*#</code> should be used. Examples:
Examples:
1. {{m|uk|о́бласть||oblast, province}} is stem-stressed everywhere but in the genitive plural, which has the form ''областе́й'' instead of expected ''*о́бластей''. This can be specified as follows:
:{{temp|uk-ndecl|о́бласть<F.#>}}
which produces
{{uk-ndecl|о́бласть<F.#>}}
2. {{m|uk|ма́сло||butter}} is stem-stressed in the singular and end-stressed in the plural (i.e. stress pattern <code>c</code>), except for the genitive plural, which has the form ''ма́сел'' instead of expected ''*масе́л''. This can be specified as follows:
:{{temp|uk-ndecl|ма́сло<c*#>}}
which produces
{{uk-ndecl|ма́сло<c*#>}}
Here we also supply <code>*</code> to indicate that the noun is reducible (i.e. it has an extra vowel in the genitive plural, whose ending does not begin with a vowel).
3. {{m|uk|голова́||head}} mostly follows stress pattern <code>d'</code> (end-stressed in the singular except for the accusative singular, and stem-stressed in the plural), but has unexpected genitive plural ''голі́в'' instead of ''*го́лів'' or ''*го́лов''. Here, there is also an ''о''-''і'' vowel alternation, which is specified using the <code>i</code> code (described later). This can be specified as follows:
:{{temp|uk-ndecl|голова́<d'#.i>}}
which produces
{{uk-ndecl|голова́<d'#.i>}}
Note that technically, the ''і'' in the genitive plural is part of the stem, and there is no ending. In the case where <code>#</code> calls for ending stress and there is no ending to be stressed, the stress moves onto the last syllable of the stem.
3. {{m|uk|сестра́||sister}} follows stress pattern <code>d</code> and is reducible, hence the expected genitive plural is ''се́стер''. This does occur, but so does the opposite-stress form ''сесте́р''. To specify this, use a specification as follows:
:{{temp|uk-ndecl|сестра́<*,*#.pr>}}
which produces
{{uk-ndecl|сестра́<*,*#.pr>}}
Here we specify two stress indicators, <code>*</code> (reducible and with normal genitive plural stress) and <code>*#</code> (reducible with reversed genitive plural stress). Because the stress pattern itself is left out, it defaults to <code>d</code> (the default for feminines with ending stress in the lemma form). We also have to specify the animacy indicator <code>pr</code> because this is a personal noun (see the next section).
==Adjectival indicator==
To indicate that a noun declines as if it were an adjective, use <code>+</code>. An example is {{m|uk|лю́тий||February}} (genitive singular ''лю́того''):
:{{temp|uk-ndecl|лю́тий<+>}}
which produces
{{uk-ndecl|лю́тий<+>}}
Other indicators, such as animacy and number, can be included as necessary. An example is {{m|uk|вагі́тна||pregnant woman}}, which is a personal noun:
:{{temp|uk-ndecl|вагі́тна<+.pr>}}
which produces
{{uk-ndecl|вагі́тна<+.pr>}}
Soft adjectival nouns will automatically be recognized by their ending, such as with {{m|uk|майбу́тнє||the future}} (genitive singular ''майбу́тнього''):
:{{temp|uk-ndecl|майбу́тнє<+.sg>}}
which produces
{{uk-ndecl|майбу́тнє<+.sg>}}
==Animacy==
Animacy is specified using <code>pr</code> for personal nouns and <code>anml</code> for animal nouns. The code <code>inan</code> for inanimate nouns can be given, but is essentially never needed because nouns normally default to inanimate. The only exception is when the neuter variant code <code>t</code> is given; all such nouns refer to the young of animals, and default to <code>anml</code> animacy.
Examples:
1. {{m|uk|бана́н||banana}} is inanimate, so the animacy doesn't need to be given:
:{{temp|uk-ndecl|бана́н<>}}
which produces
{{uk-ndecl|бана́н<>}}
2. {{m|uk|ри́ба||fish}} is an animal noun, so the animacy code <code>anml</code> needs to be specified:
:{{temp|uk-ndecl|ри́ба<anml>}}
which produces
{{uk-ndecl|ри́ба<anml>}}
Note here that the accusative plural has two forms, one identical to the nominative plural and the other identical to the genitive plural; this is characteristic of animal nouns.
3. {{m|uk|біс||demon}} is a personal noun (human-like mythological creatures are considered personal; similarly, animal-like mythological creatures such as dragons are considered animal nouns). Thus the animacy code <code>pr</code> needs to be specified:
:{{temp|uk-ndecl|біс<pr>}}
which produces
{{uk-ndecl|біс<pr>}}
Note here that the accusative singular and plural are identical to the genitive singular and plural, respectively. All personal nouns behave this way in the plural, and all masculine personal and animal nouns behave this way in the singular.
4. {{m|uk|порося́||piglet}} is an animal noun of the ''t''-stem type (genitive singular ''порося́ти'', nominative plural ''порося́та''). Once <code>t</code> is specified, the animacy doesn't need to be given because code <code>t</code> implies animacy <code>anml</code>:
:{{temp|uk-ndecl|порося́<t>}}
which produces
{{uk-ndecl|порося́<t>}}
5. {{m|uk|дівча́||girl (endearing)}} is a personal noun of the ''t''-stem type (genitive singular ''дівча́ти'', nominative plural ''дівча́та''). Code <code>t</code> implies <code>anml</code>, so <code>pr</code> must be given:
:{{temp|uk-ndecl|дівча́<pr.t>}}
which produces
{{uk-ndecl|дівча́<pr.t>}}
==Number==
By default, all nouns are singular/plural, including proper nouns. (Many proper nouns, such as names and surnames, have plural forms.) To indicate that a noun is singular-only, use <code>sg</code>, as with {{m|uk|ха́ос||chaos, mess}}:
:{{temp|uk-ndecl|ха́ос<sg>}}
which produces
{{uk-ndecl|ха́ос<sg>}}
Note that singular-only nouns are sometimes declined differently from singular/plural nouns. For example, for masculine nouns the genitive singular defaults to ''-у'' instead of ''-а'', and the locative singular defaults to either ''-у'' or ''-і'' instead of just ''-і''.
To indicate that a noun is plural-only, use <code>pl</code> and give the lemma in its plural form, as with {{m|uk|вуста́||mouth, lips}}:
:{{temp|uk-ndecl|вуста́<pl>}}
which produces
{{uk-ndecl|вуста́<pl>}}
In the above case, the module automatically knows that the noun is neuter by its ending. However, if the lemma ends in ''-и'' or ''-і'', you will have to give the gender explicitly (<code>M</code> or <code>F</code>), so that the module knows how to generate the genitive plural. If you are not sure of the gender, look for a related singular/plural noun or for cognate nouns in other languages (especially Russian), or base the gender on the genitive plural (<code>M</code> if the genitive plural ends in ''-ів'', <code>F</code> if the genitive plural ends in nothing, in ''-ь'' or in ''-ей''). An example is {{m|uk|джу́нглі||jungle}}, which should be indicated as masculine because its genitive plural is ''джу́нглів'':
:{{temp|uk-ndecl|джу́нглі<M.pl>}}
which produces
{{uk-ndecl|джу́нглі<M.pl>}}
Another example is {{m|uk|коно́плі||hemp}}, which is shown to be feminine by its genitive plural ''конопе́ль'' as well as by the cognate {{m|ru|конопля́}} in Russian, which is singular/plural and feminine:
:{{temp|uk-ndecl|коно́плі<F.*#.pl>}}
which produces
{{uk-ndecl|коно́плі<F.*#.pl>}}
Note here that the noun is reducible, with reversed genitive plural stress, as indicated by <code>*#</code>.
Some feminine plural-only nouns belong to the third declension, i.e. their singular equivalent would end in a consonant or ''-ь'' rather than ''-а'' or ''-я''. This is shown most clearly by a genitive plural in ''-ей''. An example is {{m|uk|две́рі||door(s)}}, with genitive plural ''двере́й'' (compare {{cog|ru|дверь}}). This should be indicated using the code <code>3rd</code>. This automatically implies <code>F</code>, which doesn't need to be given explicitly:
:{{temp|uk-ndecl|две́рі<#.pl.3rd.insplýma:mý>}}
which produces
{{uk-ndecl|две́рі<#.pl.3rd.insplýma:mý>}}
Here, the genitive plural has reversed stress (''двере́й'' instead of expected ''*две́рей''), and the instrumental plural is irregular.
==Softness and hardness==
Most of the time, whether a noun is soft, semisoft or hard can be determined automatically from the ending. Occasionally, however, this isn't the case (e.g. with nouns ending in ''-р''). In addition, some nouns are hard in the singular and soft in the plural, or vice-versa. Special codes are provided for these cases.
By default, nouns in ''-р'' are hard. To specify that such a noun is soft, use <code>soft</code>. An example is {{m|uk|бібліоте́кар||librarian}} (genitive singular ''бібліоте́каря'', nominative plural ''бібліоте́карі'', etc.):
:{{temp|uk-ndecl|бібліоте́кар<pr.soft>}}
which produces
{{uk-ndecl|бібліоте́кар<pr.soft>}}
A few nouns in ''-р'' are semisoft, meaning they take endings similar to nouns that end in a hushing consonant (one of ''ч ж ш щ''). An example is {{m|uk|батя́р||ruffian}} (genitive singular ''батяра́'' but instrumental singular ''батяре́м'', nominative plural ''батярі́'', etc.):
:{{temp|uk-ndecl|батя́р<b.pr.semisoft>}}
which produces
{{uk-ndecl|батя́р<b.pr.semisoft>}}
A fourth type of noun in ''-р'' is hard except for the nominative plural, which is ''-і'' rather than expected ''*-и''. An example is {{m|uk|кома́р||mosquito}}. To indicate this type, use an override (see below):
:{{temp|uk-ndecl|кома́р<b.anml.nompli>}}
which produces
{{uk-ndecl|кома́р<b.anml.nompli>}}
A small number of nouns are hard in the singular but soft in the plural, or vice-versa. These nouns generally have other irregularities, such as having a different stem in the plural. An example is {{m|uk|друг||friend}}, which has soft endings in the plural based off of a stem ''друз-'' (nominative plural ''дру́зі'', instrumental plural ''дру́зями'', etc.):
:{{temp|uk-ndecl|друг<pr.plsoft.plstem:друз.voce>}}
which produces
{{uk-ndecl|друг<pr.plsoft.plstem:друз.voce>}}
Here we specify:
# <code>pr</code> to indicate that this is a personal noun (accusative singular and plural are the same as the genitive singular and plural, respectively);
# <code>plsoft</code> to indicate that this noun has soft endings in the plural;
# <code>plstem:друз</code> to specify the irregular plural stem;
# <code>voce</code> to override the vocative singular, giving it an ending ''-е'' instead of the normal ending ''-у'' for nouns ending in a velar. (This automatically triggers the {{w|Slavic first palatalization}}, giving the form ''дру́же''. See below under [[#Automatic palatalization of velars|automatic palatalization of velars]].)
==Vowel alternations==
Similar to reducible alternations, some nouns have alternations between ''і'' and either ''о'' or ''е''. Generally the ''і'' appears in the last syllable of a word with an ending not beginning with a vowel (similar to the reducible variant where a fill vowel is present), and the ''о'' or ''е'' appears in its place with an ending beginning with a vowel (similar to the reducible variant with no fill vowel). The cognate words in Russian and Polish generally have an ''о'' or ''е'' in all forms, showing that the ''і'' is a Ukrainian-specific development. An example is {{m|uk|о́бід||rim}}, with genitive singular ''о́бода'', nominative plural ''о́боди'', etc. This is indicated using <code>io</code> to specify that an ''і'' in the lemma changes into an ''о'' in forms with an ending beginning with a vowel:
:{{temp|uk-ndecl|о́бід<io>}}
which produces
{{uk-ndecl|о́бід<io>}}
In some nouns, the sequence ''лі'' changes to ''льо'' rather than ''ло''. To indicate this change, use <code>ijo</code>, as in {{m|uk|вертолі́т||helicopter}}, with genitive singular ''вертольо́та'':
:{{temp|uk-ndecl|вертолі́т<ijo>}}
which produces
{{uk-ndecl|вертолі́т<ijo>}}
Examples of other nouns with this change are {{m|uk|лід||ice}}, {{m|uk|ко́лір||color}}. Note that in some nouns, ''лі'' changes to ''ло'', e.g. {{m|uk|плід||fruit}}, {{m|uk|пліт||raft}}, {{m|uk|глід||hawthorn}}, {{m|uk|барлі́г||bear's lair}}.
To indicate that the ''і'' changes into an ''е'', use <code>ie</code>, as in {{m|uk|ведмі́дь||bear}}, with genitive singular ''ведме́дя'':
:{{temp|uk-ndecl|ведмі́дь<M.anml.ie>}}
which produces
{{uk-ndecl|ведмі́дь<M.anml.ie>}}
The code <code>ie</code> should also be used for nouns with orthographic ''ї'' that changes into ''є'', as in {{m|uk|Ки́їв||Kyiv}}, with genitive singular ''Ки́єва'':
:{{temp|uk-ndecl|Ки́їв<sg.ie.datu>}}
which produces
{{uk-ndecl|Ки́їв<sg.ie.datu>}}
(<code>datu</code> is a [[#Specific form overrides|specific form override]].)
Feminines in ''-а'' and ''-я'', and neuters in ''-о'', ''-е'' and ''-я'', that have a vowel alternation will have it in the opposite direction, with an ''о'' or ''е'' in the lemma changing into an ''і'' in the genitive plural. This should be indicated using <code>i</code>, as in {{m|uk|шко́ла||school}}, with genitive plural ''шкіл'':
:{{temp|uk-ndecl|шко́ла<i>}}
which produces
{{uk-ndecl|шко́ла<i>}}
Note that feminines ending in a consonant or in ''-ь'' will have the same sort of alternation as in masculines, for example {{m|uk|річ||thing}} with genitive ''ре́чі'':
:{{temp|uk-ndecl|річ<F.e.ie>}}
which produces
{{uk-ndecl|річ<F.e.ie>}}
Such nouns have the ''і'' variant not only in the nominative and accusative singular but also in the instrumental singular, here ''рі́ччю''.
Some reducible masculine nouns have an ''о'' or ''е'' in the lemma that changes into an ''і'' in most other forms, the opposite of the pattern of the majority of masculine nouns. An example is {{m|uk|вдове́ць||widower}}, with genitive singular ''вдівця́'':
:{{temp|uk-ndecl|вдове́ць<*.pr.i>}}
which produces
{{uk-ndecl|вдове́ць<*.pr.i>}}
==Special variants==
There are various miscellaneous codes that can be used to indicate special variant declensions.
===Nouns in ''-ин''===
Some nouns in ''-ин'' lose this ending in the plural. An example is {{m|uk|кия́нин||Kyivan}} (nominative plural ''кия́ни''). For these nouns, use <code>in</code>:
:{{temp|uk-ndecl|кия́нин<pr.in>}}
which produces
{{uk-ndecl|кия́нин<pr.in>}}
These nouns have an empty genitive plural ending in place of normal ''-ів'' (e.g. ''кия́н'').
If the stress is on the ending, it automatically moves to the preceding syllable in the plural. An example is {{m|uk|християни́н||Christian}} (nominative plural ''христия́ни''). See [[#Spec alternations#spec alternations]] for an example showing how this noun is declined.
===Third-declension feminine nouns===
Third-declension feminine nouns are those whose singular ends in ''-ь'' or a consonant rather than ''-я'' or ''-а''. Normally this is autodetected, but this is not possible in the plural, where the ending ''-і'' is the same as for nouns ending in ''-я''. To indicate this type of noun, use <code>3rd</code>. See the section on [[#Number|number]] for an example.
===Surnames===
Use <code>surname</code> to indicate that the noun is a surname, in which case the vocative singular can be the same as the nominative singular in addition to its normal form. An example is {{m|uk|Януко́вич||Yanukovych}}:
:{{temp|uk-ndecl|Януко́вич<surname>}}
which produces
{{uk-ndecl|Януко́вич<surname>}}
The use of <code>surname</code> automatically implies <code>pr</code>, since surnames almost always refer to people and hence are personal nouns.
===t-stem neuters===
Use <code>t</code> to indicate a ''t''-stem neuter noun, i.e. a neuter noun that ends in ''-я'' and has a stem ''-ят'' in most forms. An example is {{m|uk|ягня́||lamb}} (genitive singular ''ягня́ти'', nominative plural ''ягня́та''):
:{{temp|uk-ndecl|ягня́<t>}}
which produces
{{uk-ndecl|ягня́<t>}}
Note that <code>t</code> automatically implies <code>anml</code> and <code>N</code>, as nouns of this form are always neuter and usually refer to the young of animals. An exception where animacy <code>pr</code> needs to be given is {{m|uk|дівча́||girl (endearing)}}, which is a personal ''t''-stem neuter; see [[#Animacy|animacy]] for the declension of this noun. Another such exception is {{m|uk|курча́та||small cracks in the weathered skin of the feet, hands or face}} (literally "young chickens"; plural of {{m|uk|курча́||chick, young chicken}}). This can be indicated as follows:
:{{temp|uk-ndecl|курча́та<pl.inan.t>}}
which produces
{{uk-ndecl|курча́та<pl.inan.t>}}
===en-stem neuters===
Use <code>en</code> to indicate an ''en''-stem neuter noun, i.e. a neuter noun that ends in ''-м'я'' and has an alternative stem ''-ен'' in most forms. An example is {{m|uk|ви́м'я||udder}} with alternative genitive/dative/locative singular ''ви́мені'' and alternative instrumental singular ''ви́менем'':
:{{temp|uk-ndecl|ви́м'я<en>}}
which produces
{{uk-ndecl|ви́м'я<en>}}
As with <code>t</code>, <code>en</code> automatically implies <code>N</code>.
==Stem overrides==
Some nouns have an irregular stem compared with the lemma, either in all forms whose ending begins with a vowel or in all plural forms. An example of the former is {{m|uk|ти́ждень||week}}, with stem ''тижн-'' (e.g. genitive singular ''ти́жня'', nominative plural ''ти́жні''). To specify this, use <code>stem:STEM</code>:
:{{temp|uk-ndecl|ти́ждень<M.*.stem:тижн>}}
which produces
{{uk-ndecl|ти́ждень<M.*.stem:тижн>}}
Note here that we specify <code>*</code> to indicate a reducible noun, even though we override the stem. It's not actually necessary to specify <code>*</code>, but it affects the categorization and what is displayed in the title bar.
Some nouns, especially neuter nouns, have a distinct stem in the plural. An example is {{m|uk|де́рево||tree}}, with plural stem ''дере́в-'' (note the stress), e.g. nominative plural ''дере́ва''. To specify this, use <code>plstem:STEM</code>:
:{{temp|uk-ndecl|де́рево<plstem:дере́в>}}
which produces
{{uk-ndecl|де́рево<plstem:дере́в>}}
==Specific form overrides==
Specific forms can be overridden. The way to specify this is either <code>SLOT''ENDING:ENDING:...''</code> to specify the ending(s) of a given slot (i.e. a case/number combination), <code>SLOT:''FORM:FORM:...''</code> to specify the whole form(s) of a given slot. Note the difference: When specifying endings, attach the ending(s) directly to the slot name, while when specifying forms, separate the slot name and form(s) with a colon. In both cases, separate endings and forms from each other using a colon. The endings and forms can be given either using Cyrillic letters or transliterated Roman letters; in the latter case, the Roman letters are reverse-transliterated to get the Cyrillic. The use of Roman letters is conventional when specifying endings, because these sorts of overrides are much more frequent than full form overrides, and Roman letters are easier to type when the slot name is also written using Roman letters.
===Ending overrides===
An example override is <code>genu</code>, which specifies that the genitive singular ends in ''-у'' (transliterated ''-u''). This particular override is extremely frequent, as entire classes of masculine nouns require genitive in ''-у'' instead of the default ''-а''. An example is {{m|uk|вокза́л||train station}}:
:{{temp|uk-ndecl|вокза́л<genu>}}
which produces
{{uk-ndecl|вокза́л<genu>}}
Normally, an ending override overrides the ending itself but not the stress pattern, which remains as it would normally be. For example, when <code>genu</code> is used with a noun of stress pattern <code>b</code>, the ending will be stressed, as is normal for this stress pattern. An example is {{m|uk|бур'я́н||weed}}:
:{{temp|uk-ndecl|бур'я́н<b.genu>}}
which produces
{{uk-ndecl|бур'я́н<b.genu>}}
To explicitly specify ending stress, place an accent on the ending, as with {{m|uk|вид||face, appearance}}, which is stem-stressed (pattern <code>a</code>) except that it has an irregular locative ''виду́'':
:{{temp|uk-ndecl|вид<genu.locú>}}
which produces
{{uk-ndecl|вид<genu.locú>}}
To explicitly specify stem stress when the stress pattern calls for ending stress, place an accent on the vowel of the slot name, as with {{m|uk|суд||court (of law)}}, which is ending-stressed (pattern <code>b</code>) except that it has an irregular genitive ''су́ду'':
:{{temp|uk-ndecl|суд<b.génu>}}
which produces
{{uk-ndecl|суд<b.génu>}}
As mentioned above, separate multiple endings with a colon, as with {{m|uk|очере́т||reed}}, which irregularly has locative singular either ''очере́ту'' or ''очере́ті'' and nominative plural either ''очере́та'' or ''очере́ти'':
:{{temp|uk-ndecl|очере́т<locu:i.nompla:y>}}
which produces
{{uk-ndecl|очере́т<locu:i.nompla:y>}}
In more complicated cases, a given slot can be listed more than once. For example, {{m|uk|стіл||table}} mostly follows stress pattern <code>b</code>, but has irregular genitive either ''стола́'' or ''сто́лу''. This can be specified as follows:
:{{temp|uk-ndecl|стіл<b.io.gena.génu.loci:u>}}
which produces
{{uk-ndecl|стіл<b.io.gena.génu.loci:u>}}
Note that for clarity, the genitive singular overrides could also be given as <code>gená.génu</code> to make the stress pattern of these forms completely clear.
===Full overrides===
Most irregularities in Ukrainian nouns involve irregular endings, but occasionally an irregular stem appears as well. If the irregular stem appears throughout the plural, or throughout the singular and plural except for the lemma, a stem override can be used (see above), but if the irregular stem is in only one or two forms, a full form override must be used. An example is {{m|uk|стаття́||article, item}}, with irregular genitive plural ''стате́й'':
:{{temp|uk-ndecl|стаття́<F.b.genpl:стате́й>}}
which produces
{{uk-ndecl|стаття́<F.b.genpl:стате́й>}}
Here we specify the gender <code>F</code> (otherwise the noun would be inferred as neuter), and the stress pattern <code>b</code> (otherwise the noun would be inferred as pattern <code>d</code>).
Another example involving the genitive plural is {{m|uk|вівця́||sheep}}, with irregular genitive plural ''ове́ць'':
:{{temp|вівця́<*.anml.genpl:ове́ць>}}
which produces
{{uk-ndecl|вівця́<*.anml.genpl:ове́ць>}}
===Null and missing overrides===
To specify that a given form has a null ending, use <code>-</code> as the ending. An example is {{m|uk|хоза́р||Khazar}}, which has genitive plural either ''хоза́р'' (with a null ending) or ''хоза́рів'' (with the regular ending ''-ів''):
:{{temp|хоза́р<pr.genpl-:iv>}}
which produces
{{uk-ndecl|хоза́р<pr.genpl-:iv>}}
When <code>-</code> is used in a full override, it indicates that this particular form is entirely missing. An example is {{m|uk|ага́||aga, agha (Turkish honorific)}}, which per [https://goroh.pp.ua/%D0%A1%D0%BB%D0%BE%D0%B2%D0%BE%D0%B7%D0%BC%D1%96%D0%BD%D0%B0/%D0%B0%D0%B3%D0%B0 Goroh Slovozmina] has no genitive plural:
:{{temp|uk-ndecl|ага́<b.pr.genpl:->}}
which produces
{{uk-ndecl|ага́<b.pr.genpl:->}}
Note the difference between this and the preceding example. This example uses a full override (colon directly follows <code>genpl</code>), while the preceding example uses an ending override (no colon directly after <code>genpl</code>).
Missing overrides can be useful in [[#Spec alternations|spec alternations]] in place of a full or ending override, when the other of the two alternatives in the alternation already specifies all the possible forms for a given slot. See [[#More complex examples|more complex examples]] for an example of this.
===Overrides and derived forms===
Certain forms are derived from others, in that the forms in one slot are copied to another slot. Specifically:
* The accusative plural of all nouns is derived from either the nominative singular, the genitive singular or both, depending on animacy.
* The vocative plural of all nouns is derived from the nominative plural.
* The accusative singular of masculine nouns is derived from either the nominative singular or genitive singular, depending on animacy.
* The vocative singular of surnames (those with the <code>surname</code> code) is derived from the nominative singular ''in addition to'' whatever the form would normally be.
This has implications for overrides. Specifically, overrides of source slots (nominative singular, genitive singular, nominative plural, genitive plural) are implemented ***before*** copying to derived slots, but overrides of derived slots (accusative singular, accusative plural, vocative singular, vocative plural) are implemented ***after*** copying. This means that overrides of source slots such as the nominative and genitive plural will automatically be propagated to the slots derived from them, but overrides of derived slots is still possible.
For example, in the preceding example with {{m|uk|вівця́||sheep}}, where a genitive plural override ''ове́ць'' was given, the accusative plural will also have ''ове́ць'' as one of the two possibilities (along with ''ві́вці'', derived from the nominative plural). Similarly, in the earlier example above with {{m|uk|очере́т||reed}}, where a nominative plural ending override <code>nompla:y</code> is given to specify that the nominative plural should be either ''очере́та'' or ''очере́ти'', both forms will also be found in the accusative and vocative plural.
An example of overriding a derived slot is {{m|uk|пан||lord, sir}}, which has an irregular alternative vocative plural ''пано́ве'' as well as the regular vocative plural ''пани́'' derived from the nominative plural. This can be specified as follows:
:{{temp|пан<c.pr.locovi:u.vocply:ove>}}
which produces
{{uk-ndecl|пан<c.pr.locovi:u.vocply:ove>}}
===Slot names for overrides===
The slot names are as follows:
{|class="wikitable"
! Case !! Singular !! Accented variant !! Plural !! Accented variant
|-
| Nominative || <code>nom</code> || <code>nóm</code> || <code>nompl</code> || <code>nómpl</code>
|-
| Genitive || <code>gen</code> || <code>gén</code> || <code>genpl</code> || <code>génpl</code>
|-
| Dative || <code>dat</code> || <code>dát</code> || <code>datpl</code> || <code>dátpl</code>
|-
| Accusative || <code>acc</code> || <code>ácc</code> || <code>accpl</code> || <code>áccpl</code>
|-
| Instrumental || <code>ins</code> || <code>íns</code> || <code>inspl</code> || <code>ínspl</code>
|-
| Locative || <code>loc</code> || <code>lóc</code> || <code>locpl</code> || <code>lócpl</code>
|-
| Vocative || <code>voc</code> || <code>vóc</code> || <code>vocpl</code> || <code>vócpl</code>
|}
===Automatic palatalization of velars===
Certain endings, when used as overrides (as well as when they are the default), automatically trigger the {{w|Slavic first palatalization}} or {{w|Slavic second palatalization}} of velar consonants. Specifically:
* The ending ''-е'' in the vocative singular triggers the Slavic first palatalization.
* The ending ''-і'' in the dative or locative singular triggers the Slavic second palatalization.
The palatalizations are as follows:
{|class="wikitable"
! Letter !! First palatalization !! Second palatalization
|-
| к || ч || ц
|-
| г || ж || з
|-
| х || ш || с
|-
| ц || ч || ц
|}
An example is {{m|uk|чолові́к||man}}. The default vocative singular ending for masculines ending in a velar is ''-у'', but this noun has vocative singular ''чолові́че''. To specify this, just use a regular ending override <code>voce</code>, and the first palatalization will automatically apply, converting ''к'' into ''ч'':
:{{temp|uk-ndecl|чолові́к<pr.voce>}}
which produces
{{uk-ndecl|чолові́к<pr.voce>}}
Another example is {{m|uk|ріг||horn (object)}}. The default locative singular ending for inanimate masculines ending in a velar is ''-у'', but this noun has locative singular ''ро́зі''. As above, use a regular ending override <code>loci</code>, and the second palatalization will automatically apply:
:{{temp|uk-ndecl|ріг<io.loci>}}
which produces
{{uk-ndecl|ріг<io.loci>}}
==Default forms for specific slots==
The rules for which endings are used by default in specific slots (e.g. locative singular) are fairly complicated. This is because Ukrainian nouns are complex, often with multiple possible endings allowed for a given slot and with many exceptions.
===Genitive singular===
* Masculine nouns default to ''-а'' (or ''-я'' for soft nouns) in most cases, but default to ''-у'' (or ''-ю'' for soft nouns) in singular-only common nouns (not singular-only proper nouns). The default of ''-а''/''-я'' is correct for essentially all animate nouns, and the default of ''-у''/''-ю'' is correct for almost all singular-only common nouns. However, there are many inanimate singular/plural common nouns, and many inanimate proper nouns, that need a <code>genu</code> or <code>genju</code> override. The particular ending used is a function of the semantic category of the noun. For example, names of cities use ''-а''/''-я'', but names of states and countries use ''-у''/''-ю''; words referring to most types of objects use ''-а''/''-я'', but words referring to materials use ''-у''/''-ю''. Hence, {{m|uk|Алжи́р||Algiers}} (a city) uses ''-а'', but {{m|uk|Алжи́р||Algeria}} (a country) uses ''-у'', and {{m|uk|ріг||horn (object)}} uses ''-а'', but {{m|uk|ріг||horn (material)}} uses ''-у''.
===Locative singular===
The rules for the locative singular of masculine nouns are quite complex.
* For velar-stem nouns:
*# Animate nouns use either ''-ові'' or ''-у''.
*# Reducible inanimate nouns also use either ''-ові'' or ''-у''.
*# Non-reducible inanimate nouns use ''-у''.
* For non-velar hard-stem nouns:
*# Animate nouns use either ''-ові'' or ''-і''.
*# Inanimate singular-only nouns use either ''-у'' or ''-і''.
*# Inanimate singular/plural nouns use ''-і''.
* For soft-stem nouns:
*# Animate nouns use either ''-еві'', ''-ю'' or ''-і''.
*# Inanimate nouns use either ''-ю'' or ''-і''.
* Semisoft-stem nouns are analogous to soft-stem nouns:
*# Animate nouns use either ''-еві'', ''-у'' or ''-і''.
*# Inanimate nouns use either ''-у'' or ''-і''.
===Vocative singular===
FILL IN
===Genitive plural===
FILL IN
==Spec alternations==
Some nouns have declensions with multiple possible stress patterns, or which appear to be composed of the union of multiple individual declensions. This can be handled using a ''spec alternation''. A basic example is {{m|uk|апо́строф||apostrophe}}, also stressable as {{m|uk|апостро́ф}}:
:{{temp|uk-ndecl|((апо́строф<>,апостро́ф<>))}}
which produces
{{uk-ndecl|((апо́строф<>,апостро́ф<>))}}
Note the format: Two (or more) full declension specifications, comma-separated, surrounded by double parentheses.
If both declensions overlap in some forms, the forms will be deduplicated, and will only appear once. For example, {{m|uk|христия́нин}} has nominative plural ''христия́ни'' (where ''-ин'' disappears in the plural), and has an alternative stress pattern {{m|uk|християни́н}}, with the same nominative plural ''христия́ни'' (here again, ''-ин'' disppears in the plural, and since it is stressed, the stress moves onto the previous syllable). This can be specified as follows:
:{{temp|uk-ndecl|((христия́нин<pr.in>,християни́н<pr.in>))}}
which produces
{{uk-ndecl|((христия́нин<pr.in>,християни́н<pr.in>))}}
Note how the plural has only one form per slot.
There is no requirement that the lemmas in the two alternative specifications have different stress patterns, or that the associated specifications inside of <code><...></code> are the same. For example, {{m|uk|сту́пінь||step}} has two alternative declensions, one with an ''і'' -> ''е'' alternation (genitive singular ''сту́пеня'') and the other with vowel reduction (genitive singular ''сту́пня''). This can be specified as follows:
:{{temp|uk-ndecl|((сту́пінь<M.ie>,сту́пінь<M.*>))}}
which produces
{{uk-ndecl|((сту́пінь<M.ie>,сту́пінь<M.*>))}}
==Footnotes==
Footnotes can be attached in any of the following three places:
* Onto an entire spec, applying to all forms generated by that spec. This is most useful when multiple alternative specs are used in a [[#Spec alternations|spec alternation]].
* Onto a stress pattern, applying to all forms generated by the stress pattern.
* Onto an individual override, applying to that form.
An example is {{m|uk|пе́рстень||ring}}, where the normal stem used in most forms is ''персн-''. Regular forms using the stem ''пе́рстен-'' also exist but are rare. Specify this as follows:
:{{temp|uk-ndecl|((пе́рстень<M.*.stem:персн>,пе́рстень<M.[rare]>))}}
which produces
{{uk-ndecl|((пе́рстень<M.*.stem:персн>,пе́рстень<M.[rare]>))}}
Here, we attach a footnote "rare" to the second of two specs in a spec alternation. The effect of this is that all forms generated by the second spec that are ***not*** also present in the first spec will have this footnote. (Hence, nominative and accusative singular ''пе́рстень'' will not have it.)
Another example that attaches a footnote to a single override is with {{m|uk|вік||age, lifetime}}, which has two locative singular forms, ''ві́ці'' (used with {{m|uk|у}}) and ''віку́'' (used with {{m|uk|на}}). To indicate this, we can attach a footnote to the second form as follows:
:<code><nowiki>{{uk-ndecl|вік<sg.loci:ú[''ві́ці'' is normally used with {{m|uk|у}}, and ''віку́'' with {{m|uk|на}}]>}}</nowiki></code>
which produces
{{uk-ndecl|вік<sg.loci:ú[''ві́ці'' is normally used with {{m|uk|у}}, and ''віку́'' with {{m|uk|на}}]>}}
Note that nested brackets, angle brackets, braces, etc. can occur inside the footnote as long as they are properly paired.
==More complex examples==
1. {{m|uk|штани́||trousers, pants}} has the following forms:
* Nominative/accusative/vocative plural: ''штани́''
* Genitive plural: ''штані́в''
* Dative plural: ''шта́ням, штана́м''
* Instrumental plural: ''шта́нями, штана́ми, штаньми́''
* Locative plural: ''шта́нях, штана́х''
The dative, instrumental and locative plural have both soft and hard endings, with different stress patterns. This suggests that a [[#Spec alternations|spec alternation]] could be used. Since the nominative plural only has hard endings, the soft alternative needs to use a soft-ending lemma and override the nominative plural. The result is as follows:
:{{temp|uk-ndecl|((шта́ні<M.#.pl.nompl:->,штани́<M.pl.insplamy:ьmy>))}}
which produces
{{uk-ndecl|((шта́ні<M.#.pl.nompl:->,штани́<M.pl.insplamy:ьmy>))}}
The first alternative captures the soft stem-stressed forms, with a missing nominative plural override (see [[#Null and missing overrides|null and missing overrides]] above) and the reversed genitive-stress indicator <code>#</code>. The second alternative captures the hard ending-stressed forms, and specifies an instrumental plural override to capture the additional form ''штаньми́''.
2. {{m|uk|чо́біт||boot}} has mostly regular forms in the singular, with an ''і''-''о'' vowel alternation (e.g. genitive singular ''чо́бота'') but has irregular locative singular ''чо́боту, чо́боті'' as well as the following forms in the plural:
* Nominative/accusative/vocative plural: ''чо́боти''
* Genitive plural: ''чобі́т''
* Dative plural: ''чо́ботам, чобо́тям''
* Instrumental plural: ''чо́ботами, чобітьми́''
* Locative plural: ''чо́ботах, чобо́тях''
It is possible to use a spec alternation as in the previous example (where the second alternative uses <code>plsoft</code> and <code>plstem:чобо́т</code>), but in this case it may be simpler just to explicitly specify the irregular plural forms using full overrides:
:{{temp|uk-ndecl|чо́біт<io.locu:i.genpl:чобі́т.datpl:чо́ботам:чобо́тям.insplamy:ьmý.locpl:чо́ботах:чобо́тях>}}
which produces
{{uk-ndecl|чо́біт<io.locu:i.genpl:чобі́т.datpl:чо́ботам:чобо́тям.insplamy:ьmý.locpl:чо́ботах:чобо́тях>}}
Note the use of an ending override in the instrumental plural. Since the specified instrumental plural ending ''-ьми́'' does not begin with a vowel, the non-vowel alternant with ''і'' instead of ''о'' is used. A full override would also be possible; conversely, an ending override could be used in the genitive plural, with a reversed genitive-plural stress indicator, i.e. <code>#.genpl-</code>.
The shortest equivalent using a spec alternation would be as follows:
:{{temp|uk-ndecl|((чо́біт<io.#.locu:i.genpl->,чо́біт<io.plsoft.plstem:чобо́т.nompl:-.genpl:-.insplьmý>))}}
Note that this is even longer than the specification using full overrides, and harder to understand.
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်]]
</includeonly>
lffv3hlsifh0kkd5rfvdjmm21wmey0w
ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်
14
297525
399811
2026-07-21T06:03:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]"
399811
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]
hqkiahkbu6ku6n8k02qd62g7gluupth
ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
297526
399812
2026-07-21T06:04:19Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]"
399812
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ယူကရိန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ယ]]
fh5jhzovoob9vaogcd0oj9r7qm674p2
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၁
4
297527
399813
2026-07-21T06:07:01Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|злоба|နာမ်| ဂမ္တၚ်။ # စိုတ်ဟွံဒး၊ စိုတ်ပစ္ဆရိယ။ # ပရေၚ်မနောဒေါသတိတ်၊ ဒေါသ။ # စိုတ်ဂၞံၚ်ဂၞာတ်။|audio=Ru-злоба.ogg|ဂျူလာင်|၂၁}}"
399813
wikitext
text/x-wiki
{{WOTD|злоба|နာမ်| ဂမ္တၚ်။
# စိုတ်ဟွံဒး၊ စိုတ်ပစ္ဆရိယ။
# ပရေၚ်မနောဒေါသတိတ်၊ ဒေါသ။
# စိုတ်ဂၞံၚ်ဂၞာတ်။|audio=Ru-злоба.ogg|ဂျူလာင်|၂၁}}
8xn3xmxvmsekmmnojnwtvba2z1w6epf
ထာမ်ပလိက်:uk-noun/documentation
10
297528
399815
2026-07-21T06:10:04Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|Module:uk-be-headword}} This template is used for the headword line of Ukrainian nouns. ==Parameters== The following parameters are available: ; {{para|1}} : The headword of the current entry, with accents. Multiple comma-separated values can be specified, with no space after the comma. See the documentation of [[Module:uk-be-headword]] for more information. For details on the ang..."
399815
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:uk-be-headword}}
This template is used for the headword line of Ukrainian nouns.
==Parameters==
The following parameters are available:
; {{para|1}}
: The headword of the current entry, with accents. Multiple comma-separated values can be specified, with no space after the comma. See the documentation of [[Module:uk-be-headword]] for more information. For details on the angle-bracket notation (like <code>две́рі<#.3rd.pl.insplýma:mý></code>), see {{temp|uk-ndecl}}.
; {{para|2}}
: The noun's gender, specified in the format of [[Module:gender and number]]. It should be of the format <code>GENDER-ANIMACY</code>, or <code>GENDER-ANIMACY-p</code>for plural-only nouns (pluralia tantum). <code>GENDER</code> should be either <code>m</code> (masculine), <code>f</code> (feminine), <code>n</code> (neuter), <code>mf</code> (masculine or feminine, with no sense difference) or <code>mfbysense</code> (masculine or feminine by sense). <code>ANIMACY</code> should be either <code>pr</code> (personal), <code>anml</code> (animal) or <code>in</code> (inanimate). Examples: <code>m-pr</code> (masculine personal), <code>f-anml</code> (feminine animal), <code>n-in-p</code> (neuter inanimate plural-only). Multiple comma-separated values can be specified, with no space after the comma.
: If you don't know the gender, use <code>?</code> in place of the gender, and add the extra parameter {{para|unknown_gender|1}} to indicate that you really don't know the gender (otherwise the use of <code>?</code> will cause an error to be thrown). Likewise, if you don't know the animacy, use <code>?</code> in place of the animacy, along with {{para|unknown_animacy|1}}.
; {{para|3}}
: The genitive form of the noun, with accents. This is normally the genitive singular form, but it can be plural if the noun only occurs in that form. Multiple comma-separated values can be specified, with no space after the comma.
:* If the noun is indeclinable, use <code>-</code>.
; {{para|4}}
: The nominative plural form of the noun, with accents. Multiple comma-separated values can be specified, with no space after the comma.
:* If the noun has no plural (is uncountable), use <code>-</code>.
; {{para|5}}
: The genitive plural form of the noun, with accents. Multiple comma-separated values can be specified, with no space after the comma.
; {{para|f}}
: The feminine equivalent(s) of the noun, if any. Multiple comma-separated values can be specified, with no space after the comma.
; {{para|m}}
: The masculine equivalent(s) of the noun, if any. Multiple comma-separated values can be specified, with no space after the comma.
; {{para|adj}}
: The related adjective(s) of the noun, if any. This is intended for {{glossary|relational}} adjectives, e.g. {{m|uk|кашта́новий||chestnut (relational)}} as the related adjective of {{m|uk|кашта́н||chestnut}}. Multiple comma-separated values can be specified, with no space after the comma.
; {{para|dim}}
: The diminutive(s) of the noun, if any. Multiple comma-separated values can be specified, with no space after the comma.
; {{para|unknown_gender|1}}
: Signal that you don't know the gender; allows you to use <code>?</code> in place of the gender specification.
; {{para|unknown_animacy|1}}
: Signal that you don't know the animacy; allows you to use <code>?</code> in place of the animacy specification.
; {{para|unknown_stress|1}}
: Signal that you don't know the stress position; allows you to use multisyllabic terms without specifying the accent.
{{hwcat}}
==Examples==
1.
{{demo|<nowiki>{{uk-noun|о́зеро<plstem:озе́р>|adj=озе́рний|dim=озе́рце,озерце́|pagename=озеро}}</nowiki>|indent=:}}
2.
{{demo|<nowiki>{{uk-noun|верблю́д<anml>|f=верблюди́ця,верблюди́ха<l:rare>|adj=верблю́жий,верблю́дячий|pagename=верблюд}}</nowiki>|indent=:}}
3.
{{demo|<nowiki>{{uk-noun|альмана́х<genu>|adj=альмана́ховий,альмана́шний<l:dated>|pagename=альманах}}</nowiki>|indent=:}}
g5nu82kqv288ho98obxay478bu9ljuk
မဝ်ဂျူ:uk-be-headword/documentation
828
297529
399818
2026-07-21T07:28:21Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module is used for all Ukrainian and Belarusian headword-line templates. It provides a basic functionality common to all of them, but some of the templates have specific additional functionality to show genders or inflected forms. ==Accented headword== All Ukrainian and Belarusian headword-line templates use the first parameter to provide the headword, with accented vowels where present. For example: {{temp|uk-..."
399818
wikitext
text/x-wiki
This module is used for all Ukrainian and Belarusian headword-line templates. It provides a basic functionality common to all of them, but some of the templates have specific additional functionality to show genders or inflected forms.
==Accented headword==
All Ukrainian and Belarusian headword-line templates use the first parameter to provide the headword, with accented vowels where present. For example:
{{temp|uk-noun|соба́ка|m-anml}}
The parameter supports all the special features that the {{para|head}} parameter on {{temp|head}} does. So you can also use this parameter to link to individual words of a multi-word term. These words can be linked with accents still in place; the module will remove them from the page name before creating a link, just like {{temp|l}} does. If you need to specify accents in multiple alternative ways, use {{para|head2}}, {{para|head3}} and so on.
All Ukrainian and Belarusian words that have more than one syllable are expected to have accents specified. The module will check the parameter for the presence of accents, and (in the case of Ukrainian) throw an error if the accents are missing. If you really don't know the stress position, use {{para|unknown_stress|1}} to signal this. In this case, words without accents will be placed in a subcategory of [[:Category:Requests for accents in Ukrainian entries]] or [[:Category:Requests for accents in Belarusian entries]].
<includeonly>
{{module cat|uk,be}}
</includeonly>
qgek1z8ee94luvw2sqtr92l8d3ircot
399819
399818
2026-07-21T07:28:54Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:uk-be-headword/doc]] ဇရေင် [[မဝ်ဂျူ:uk-be-headword/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399818
wikitext
text/x-wiki
This module is used for all Ukrainian and Belarusian headword-line templates. It provides a basic functionality common to all of them, but some of the templates have specific additional functionality to show genders or inflected forms.
==Accented headword==
All Ukrainian and Belarusian headword-line templates use the first parameter to provide the headword, with accented vowels where present. For example:
{{temp|uk-noun|соба́ка|m-anml}}
The parameter supports all the special features that the {{para|head}} parameter on {{temp|head}} does. So you can also use this parameter to link to individual words of a multi-word term. These words can be linked with accents still in place; the module will remove them from the page name before creating a link, just like {{temp|l}} does. If you need to specify accents in multiple alternative ways, use {{para|head2}}, {{para|head3}} and so on.
All Ukrainian and Belarusian words that have more than one syllable are expected to have accents specified. The module will check the parameter for the presence of accents, and (in the case of Ukrainian) throw an error if the accents are missing. If you really don't know the stress position, use {{para|unknown_stress|1}} to signal this. In this case, words without accents will be placed in a subcategory of [[:Category:Requests for accents in Ukrainian entries]] or [[:Category:Requests for accents in Belarusian entries]].
<includeonly>
{{module cat|uk,be}}
</includeonly>
qgek1z8ee94luvw2sqtr92l8d3ircot
ကဏ္ဍ:မဝ်ဂျူဗါလာရုဇ်ဂမၠိုၚ်
14
297530
399820
2026-07-21T07:35:32Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာဗါလာရုဇ်|ဗါလာရုဇ်]] » '''မဝ်ဂ..."
399820
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာဗါလာရုဇ်|ဗါလာရုဇ်]] » '''မဝ်ဂျူဂမၠိုၚ်'''
:[[:ကဏ္ဍ:မဝ်ဂျူဂမၠိုၚ်|မဝ်ဂျူ]]ဘာသာဗါလာရုဇ်၊ မနွံကဵုလုပ်အဝေါၚ်ကုဒ် Lua နကဵုမကၠောန်ဗဒှ် ကဵု မစဳရေၚ်ယဵုဒုၚ်သ္ပမာန်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာဗါလာရုဇ်]][[ကဏ္ဍ:မဝ်ဂျူဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဗ]]
agqawsvxk5jblmvnzc8xp1mw9k3m26e
ကဏ္ဍ:နာမ်ယူကရိန်မတော်ဟွံဂွံဂမၠိုၚ်
14
297531
399821
2026-07-21T07:44:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာယူကရိန်]]"
399821
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာယူကရိန်]]
atcu5mfj8u4ady52jr2jjtv3oevlny9
ကဏ္ဍ:ကာရန်:ဗူလ်ဂရဳယာန်/ɔbɐ
14
297532
399822
2026-07-21T07:59:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာဗူလ်ဂရဳယာန်|ဗူလ်ဂရဳယာန်]]..."
399822
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာဗူလ်ဂရဳယာန်|ဗူလ်ဂရဳယာန်]] » [[:ကဏ္ဍ:ကာရန်:ဗူလ်ဂရဳယာန်|ကာရန်ဂမၠိုၚ်]] » -ɔbɐ
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာဗူလ်ဂရဳယာန်|ဗူလ်ဂရဳယာန်]]မနွံကာရန် ɔbɐ ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ဗူလ်ဂရဳယာန်|ɔbɐ]]
h8halej5sgi18dahu2rs0e2el4u7gmx
ဗီုပြၚ်သိုၚ်တၟိ:သလာဗေတ်-အခိုက်ကၞာ/zъloba
118
297533
399823
2026-07-21T08:03:56Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{reconstructed}} ==သလာဗေတ်-အခိုက်ကၞာ== ===နာမ်=== {{sla-noun|f}} # မယုတ်မာ၊ ပရေၚ်ဒှ်ယုတ်မာကြံကြ။ # ဒေါသ။ ====လဟုတ်စှ်ေ==== {{sla-decl-noun}} ===မဒုၚ်လွဳစ=== {{hrow}} ** {{desc|orv|зълоба}} *** {{desc|ru|зло́ба}} *** {{desc|uk|зло́ба|злоба́}} ** {{des..."
399823
wikitext
text/x-wiki
{{reconstructed}}
==သလာဗေတ်-အခိုက်ကၞာ==
===နာမ်===
{{sla-noun|f}}
# မယုတ်မာ၊ ပရေၚ်ဒှ်ယုတ်မာကြံကြ။
# ဒေါသ။
====လဟုတ်စှ်ေ====
{{sla-decl-noun}}
===မဒုၚ်လွဳစ===
{{hrow}}
** {{desc|orv|зълоба}}
*** {{desc|ru|зло́ба}}
*** {{desc|uk|зло́ба|злоба́}}
** {{desc|cu|-}}
**: {{desc|cu|зълоба|sclang=1}}
** {{desc|bg|зло̀ба}}
** {{desc|mk|злоба}}
** {{desc|sh|-}}
**: {{desc|sh|зло̀ба|sclang=1}}
**: {{desc|sh|zlòba|sclang=1}}
** {{desc|cs|zloba}}
** {{desc|zlw-opl|zgłoba|złoba}}
*** {{desc|pl|złoba|qq=obsolete}}
*** {{desc|rsk|злоба}}
r0jotoq6290y5h7rrgz8d4qr4n0vt8v
ထာမ်ပလိက်:sla-decl-noun/documentation
10
297534
399824
2026-07-21T08:06:27Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} ==Parameters== Optional: * {{para|g}} gender: <code>[[masculine|m]]</code> or <code>[[feminine|f]]</code> (e.g {{para|g|f}}) * {{para|n}} number: <code>[[singulare tantum|s]]</code> or <code>[[plurale tantum|p]]</code> (e.g. {{para|n|p}}) * {{para|ap}} [[w:Proto-Slavic_accent|accent paradigm]]: <code>a</code>, <code>b</code> or <code>c</code> * {{para|1}} Word, alternative of page name (e.g...."
399824
wikitext
text/x-wiki
{{documentation subpage}}
==Parameters==
Optional:
* {{para|g}} gender: <code>[[masculine|m]]</code> or <code>[[feminine|f]]</code> (e.g {{para|g|f}})
* {{para|n}} number: <code>[[singulare tantum|s]]</code> or <code>[[plurale tantum|p]]</code> (e.g. {{para|n|p}})
* {{para|ap}} [[w:Proto-Slavic_accent|accent paradigm]]: <code>a</code>, <code>b</code> or <code>c</code>
* {{para|1}} Word, alternative of page name (e.g. with accent).
** This is useful when the evidence of reflexes in the daughters is divergent and the original reconstruction cannot be determined with certainty. When there are truly variant forms of the reconstruction reconstructible, with the same meaning, they should be separated in individual articles (e.g. {{m|sla-pro|*olni}} and {{m|sla-pro|*olnę}}).
* {{para|stem}} stem type: <code>a</code>, <code>o</code>, <code>i</code>, <code>u</code>, <code>s</code>, <code>v</code>, <code>n</code>, <code>nt</code> or <code>r</code> (e.g. {{para|stem|u}})
==Types==
<div style="width: 1000px;">
{{top2}}
{| border="1" cellspacing="0" class="wikitable" style="font-size: 100%; text-align:center"
|-
! colspan="5" style="background:var(--wikt-palette-orange-4,#ffdead);" | Common stem types
|- style="text-align: right;" |
! colspan=2|Stem type
!|Example<br>lemma
!|Example template
|-
! o-stem
| style="text-align: left;" | [[:Category:Proto-Slavic_hard_masculine_o-stem_nouns|hard, m.]]<br/>[[:Category:Proto-Slavic_soft_masculine_o-stem_nouns|soft, m.]]
| style="text-align: right;" | {{l|sla-pro|*konъ|*ko<u>n</u>ъ}}<br/>{{l|sla-pro|*koňь|*ko<u>ň</u>ь}}
| style="text-align: left;" | {{temp|sla-decl-noun}}
|-
! o-stem
| style="text-align: left;" | [[:Category:Proto-Slavic_hard_neuter_o-stem_nouns|hard, n.]]<br/>[[:Category:Proto-Slavic_soft_neuter_o-stem_nouns|soft, n.]]
| style="text-align: right;" | {{l|sla-pro|*lěto|*lě<u>t</u>o}}<br/>{{l|sla-pro|*pľuťe|*pľu<u>ť</u>e}}
| style="text-align: left;" | {{temp|sla-decl-noun}}
|-
! a-stem
| style="text-align: left;" | [[:Category:Proto-Slavic hard a-stem nouns|hard]]<br/>[[:Category:Proto-Slavic soft a-stem nouns|soft]]
| style="text-align: right;" | {{l|sla-pro|*koza|*ko<u>z</u>a}}<br/>{{l|sla-pro|*koža|*ko<u>ž</u>a}}
| style="text-align: left;" | {{temp|sla-decl-noun}}
|-
! [[:Category:Proto-Slavic i-stem nouns|i-stem]]
| style="text-align: left;" | [[:Category:Proto-Slavic_masculine_i-stem_nouns|hard, m.]]<br/>[[:Category:Proto-Slavic_feminine_i-stem_nouns|f.]]
| style="text-align: right;" | {{l|sla-pro|*golǫbь|*golǫ<u>b</u>ь}}<br/>{{l|sla-pro|*gǫsь|*gǫsь}}
| style="text-align: left;" | {{temp|sla-decl-noun|g=m}}<br/>{{temp|sla-decl-noun|g=f}}
|-
! colspan=2 | [[:Category:Proto-Slavic_ī-stem_nouns|ī/j-stem]]
| style="text-align: right;" | {{l|sla-pro|*pustyni}}
| style="text-align: left;" | {{temp|sla-decl-noun}}
|}
{| border="1" cellspacing="0" class="wikitable" style="font-size: 100%; text-align:center; white-space: nowrap;"
|-
! colspan="5" style="background:var(--wikt-palette-orange-4,#ffdead);" | Rare stem types
|-
!colspan=2|Stem type
!Example<br>lemma
!Example template
|-
! u-stem
| style="text-align: left;" | [[:Category:Proto-Slavic u-stem nouns|m.]]
| style="text-align: right;" | {{l|sla-pro|*dǫbъ}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=u}}
|-
! s-stem
| style="text-align: left;" | [[:Category:Proto-Slavic s-stem nouns|n., hard]]<br>[[:Category:Proto-Slavic s-stem nouns|n., soft]]
| style="text-align: right;" | {{l|sla-pro|*oko}}<br>{{l|sla-pro|*lice}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=s}}
|-
! v-stem
| style="text-align: left;" | [[:Category:Proto-Slavic v-stem nouns|f.]]
| style="text-align: right;" | {{l|sla-pro|*cьrky}}<br/>{{l|sla-pro|*kry}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=v}}
|-
!rowspan=2 | n-stem
| style="text-align: left;" | [[:Category:Proto-Slavic n-stem nouns|m.]]
| style="text-align: right;" | {{l|sla-pro|*kamy}}<br/>{{l|sla-pro|*elenь}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=n}}
|-
| style="text-align: left;" | [[:Category:Proto-Slavic n-stem nouns|n.]]
| style="text-align: right;" | {{l|sla-pro|*sěmę}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=n}}
|-
! (n)t-stem
| style="text-align: left;" | [[:Category:Proto-Slavic nt-stem nouns|n.]]
| style="text-align: right;" | {{l|sla-pro|*agnę}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=nt}}
|-
! colspan=2 | [[:Category:Proto-Slavic r-stem nouns|r-stem]]
| style="text-align: right;" | {{l|sla-pro|*mati}}
| style="text-align: left;" | {{temp|sla-decl-noun}}
|-
! colspan=2 | [[:Category:Proto-Slavic_ī-stem_nouns|ī/ьj-stem]]
| style="text-align: right;" | {{l|sla-pro|*olni}}
| style="text-align: left;" | {{temp|sla-decl-noun|stem=ī/ьj}}
|}
{{bottom}}
</div>
==Examples==
<code><nowiki>{{sla-decl-noun|nȍťь|g=f|ap=c}}</nowiki></code>
{{sla-decl-noun|nȍťь|g=f|ap=c}}
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်|*]]
</includeonly>
4vw7zb8g32y08x36ndv97dykro804ps
မဝ်ဂျူ:sla-noun
828
297535
399825
2026-07-21T08:14:35Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "local m_utilities = require("Module:utilities") local com = require("Module:sla-common") local export = {} local lang = require("Module:languages").getByCode("sla-pro") local rfind = mw.ustring.find local rsubn = mw.ustring.gsub local rmatch = mw.ustring.match local rsplit = mw.text.split local ulower = mw.ustring.lower local uupper = mw.ustring.upper local usub = mw.ustring.sub local ulen = mw.ustring.len local ug..."
399825
Scribunto
text/plain
local m_utilities = require("Module:utilities")
local com = require("Module:sla-common")
local export = {}
local lang = require("Module:languages").getByCode("sla-pro")
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local uupper = mw.ustring.upper
local usub = mw.ustring.sub
local ulen = mw.ustring.len
local ugmatch = mw.ustring.gmatch
function export.show(frame)
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
local params = {
[1] = {alias_of = 'recons'},
recons = {default = SUBPAGENAME},
n = {default = "sdp"},
ap = {},
g = {},
stem = {},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local gender = args["g"]
local ap = args["ap"]
local nom_sg = com.canon_decompose(args["recons"])
local unom_sg = lang:stripDiacritics(nom_sg)
local stem, desinence = com.auto_accent_and_check_accents(nom_sg, ap)
local ustem, _ = com.split_stem_desinence(unom_sg)
local num = {}
if not args.n or not rfind(args.n, "^s?d?p?$") then
error("Illegal number “" .. args.n .. "”. Possible values are “s”, “d”, “p”, “sd”, “dp”, “sp”, or “sdp”.")
else
num = rsplit(args.n, "")
end
if (nom_sg == "" or desinence == "") then
error("Error: SUBPAGENAME=" .. SUBPAGENAME .. "Must only be used in the Reconstruction namespace with " .. lang:getCanonicalName() .. " reconstructions")
end
local stem_type = get_stem(args["stem"], desinence, gender, unom_sg)
if stem_type == "soft a-stem" and desinence=="i" then -- ī-stem +j/+ьj (Module:sla-noun/data declensions["soft a-stem"] doesn't let check data.args["stem"], for some reason #data.args==0)
stem = ( args["stem"] and args["stem"]=="ī/ьj" and ustem.."ьj" or com.iotate(ustem) )
end
if ap and ap ~= "a" and ap ~= "b" and ap ~= "c" then
error("Accent paradigm “" .. ap .. "” must be either “a”, “b”, or “c”")
end
local forms, title, extracats
local categories = {}
local data = {
args = args,
gender = gender,
desinence = desinence,
ap = ap,
nom_sg = nom_sg,
unom_sg = unom_sg, -- only used for *mati/*dъťi?
stem = stem,
ustem = ustem,
footnotes = {},
footnote_to_sym = {},
next_notesym = "*"
}
local declensions = require("Module:sla-noun/data")
if declensions[stem_type] then
forms, title, extracats = declensions[stem_type](data)
else
error("Internal error -- unrecognized internal stem type '" .. stem_type .. "'")
end
if extracats then
for _, cat in ipairs(extracats) do
-- table.insert(categories, lang:getCanonicalName() .. " " .. cat)
end
end
-- table.insert(categories, 1, lang:getCanonicalName() .. " " .. title .. " nouns")
if ap then
title = title .. ", accent paradigm " .. ap
-- table.insert(categories, lang:getCanonicalName() .. " nominals with accent paradigm " .. ap)
end
if #num == 1 then
if num[1] == 's' then
title = title .. ', uncountable'
-- table.insert(categories, lang:getCanonicalName() .. " singularia tantum")
elseif num[1] == 'p' then
title = title .. ', plural only'
-- table.insert(categories, lang:getCanonicalName() .. " pluralia tantum")
end
end
return make_table(forms, num, title, data.footnotes) .. m_utilities.format_categories(categories, lang)
end
function get_stem(st, desinence, gender, unom_sg)
if st then -- explicitly specified stem
if st == "o" then
if "ъ" == desinence then
return "hard masculine o-stem"
elseif "ь" == desinence then
return "soft masculine o-stem"
elseif "o" == desinence then
return "hard neuter o-stem"
elseif "e" == desinence then
return "soft neuter o-stem"
else
error("Unrecognized ending for o-stem")
end
elseif st == "a" then
if "a" ~= desinence then
error("Unrecognized ending for a-stem")
end
if rfind(unom_sg, "[cčďjľňřšťž]a$") or rfind(unom_sg, "dza$") then
return "soft a-stem"
else
return "hard a-stem"
end
elseif st == "i" then
if "ь" ~= desinence then
error("Unrecognized ending for i-stem")
end
if gender == "m" then
return "တံမအရေဝ် (-ိ/i)ပုလ္လိၚ်"
elseif gender == "f" then
return "တံမအရေဝ် (-ိ/i)ဣတ္တိလိၚ်"
else
error("Gender for i-stems must be specified through g= parameter, as \"m\" or \"f\"")
end
elseif st == "ī" or st=="ī/ьj" or st=="ī/j" then
if "i" ~= desinence then
error("Unrecognized ending for ī-stem")
end
return "soft a-stem" -- FIXME, remove this hack
--consonant stems have several names in the literature, we handle all so that editors don't have to remember which one Wiktionary prefers
elseif st == "n" then
return "n-stem"
elseif st == "nt" or st == "t" then
return "nt-stem"
elseif st == "r" then
return "r-stem"
elseif st == "s" then
return "s-stem"
elseif st == "u" then
return "u-stem"
elseif st == "v" or st == "ū" or st == "ъv" then
return "v-stem"
else
error("Unrecognized stem class " .. st)
end
-- Autodetect common stem types on the basis of desinence, preceding
-- consonant, and passed arguments (g=).
-- hard masculine o-stems always and in -ъ, and we skip u-stems (which have stem= parameter provided)
elseif "ъ" == desinence then
return "hard masculine o-stem"
-- soft masculine o-stems end in ь and are preceded by a soft, palatal consonant, except for such i-stems which will
-- always have g= parameter specified
elseif "ь" == desinence and not gender and (rfind(unom_sg, "[cčďjľňřšťž]ь$") or rfind(unom_sg, "dzь$")) then
return "soft masculine o-stem"
-- hard neuter o-stems always end in -o, and we skip s-stems in -o (which have stem= parameter provided)
elseif "o" == desinence then
return "hard neuter o-stem"
-- soft neuter o-stems always end in -e and are preceded by a soft, platal consonant, and we skip s-stems in -e
-- (which have stem= parameter provided)
elseif "e" == desinence and rfind(unom_sg, "[cčďjľňřšťž]e$") then
return "soft neuter o-stem"
-- soft a-stems are feminines and masculines (OCS junoša) that and in -a and are preceded by a soft, palatal consonant, or
-- in -i (except for words *mati and *dъťi which are handled as r-stems)
elseif ( "a" == desinence and ( rfind(unom_sg, "[cčďjľňřšťž]a$") or rfind(unom_sg, "dza$") ) )
or
( ("i" == desinence) and (unom_sg ~= "mati") and (unom_sg ~= "dъťi") ) then
return "soft a-stem"
-- hard a-stems are the ones that are not soft a-stems
elseif "a" == desinence then
return "hard a-stem"
-- i-stems ending in -ь preceded by a hard, non-palatal consonant. Gender is mandatory to distinguish between masculine and
-- feminine inflection. We skip n-stems (having stem= parameter specified), which are handled below.
elseif "ь" == desinence then
if gender == "m" then
return "တံမအရေဝ် (-ိ/i)ပုလ္လိၚ်"
elseif gender == "f" then
return "တံမအရေဝ် (-ိ/i)ဣတ္တိလိၚ်"
else
error("Gender for i-stems must be specified through g= parameter, as “m” or “f”")
end
-- in case of r-stems, there are only two nouns, so the stem= parameter might as well be superfluous
elseif (unom_sg == "mati") or (unom_sg == "dъťi") then
return "r-stem"
else
error("Unable to autodetect stem type; must specify stem=, per [[WT:ASLA]]")
end
end
local number_map = {
s = "singular",
d = "dual",
p = "plural",
}
local case_map = {
nom = "'''ပရေၚ်ပ္တိုန်စရၚ်ယၟု'''",
acc = "'''ကမ္မကာရက'''",
gen = "'''ဗဳဇဂကူ'''",
loc = "'''ခၞံဗဒှ်ဌာန်မတန်တဴ'''",
dat = "'''ပြကမ္မကာရက'''",
ins = "'''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်'''",
voc = "'''ပရေၚ်ဂယိုၚ်လမျီု'''",
}
function make_header(forms, num, title)
local frame = mw.getCurrentFrame()
local lemma = forms.nom[num[1]]
if type(lemma) ~= "table" then
-- lemma remains
elseif lemma.notesym then
lemma = lemma[1]
else
local lemmavals = {}
for _, item in ipairs(lemma) do
if type(item) == "table" then
table.insert(lemmavals, com.link_form(item[1]))
else
table.insert(lemmavals, com.link_form(item))
end
end
lemma = table.concat(lemmavals, ", ")
end
local header = { frame:expandTemplate{
title = 'inflection-table-top',
args = {
title = '[[Template:sla-decl-noun|မလဟုတ်စှ်ေ]]ဆေၚ်စပ်ကဵု ' .. lemma .. (title and " (" .. title .. ")" or "") .. '',
palette = 'blue',
tall = 'yes',
}
} ..
'|-',
'! ',
}
for _, n in ipairs(num) do
table.insert(header, '! ' .. number_map[n])
end
return table.concat(header, "\n")
end
function make_row(forms, num, case)
local row = {
"|-",
"! " .. case_map[case] .. ""
}
for _, n in ipairs(num) do
table.insert(row, "| " .. com.link_form(forms[case][n]))
end
return table.concat(row, "\n")
end
function make_footer(footnotes)
local frame = mw.getCurrentFrame()
local footnote_text = (#footnotes > 0) and table.concat(footnotes, "<br />") or ""
return frame:expandTemplate{
title = 'inflection-table-bottom',
args = {
notes = footnote_text,
}
}
end
-- Make the table
function make_table(forms, num, title, footnotes)
return table.concat(
{
make_header(forms, num, title),
make_row(forms, num, "nom"),
make_row(forms, num, "gen"),
make_row(forms, num, "dat"),
make_row(forms, num, "acc"),
make_row(forms, num, "ins"),
make_row(forms, num, "loc"),
make_row(forms, num, "voc"),
make_footer(footnotes),
},
"\n"
)
end
return export
pje6cl04ka8p4z5flh7e1u4s08iueam
399830
399825
2026-07-21T08:22:17Z
咽頭べさ
33
399830
Scribunto
text/plain
local m_utilities = require("Module:utilities")
local com = require("Module:sla-common")
local export = {}
local lang = require("Module:languages").getByCode("sla-pro")
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local uupper = mw.ustring.upper
local usub = mw.ustring.sub
local ulen = mw.ustring.len
local ugmatch = mw.ustring.gmatch
function export.show(frame)
local SUBPAGENAME = mw.loadData("Module:headword/data").pagename
local params = {
[1] = {alias_of = 'recons'},
recons = {default = SUBPAGENAME},
n = {default = "sdp"},
ap = {},
g = {},
stem = {},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local gender = args["g"]
local ap = args["ap"]
local nom_sg = com.canon_decompose(args["recons"])
local unom_sg = lang:stripDiacritics(nom_sg)
local stem, desinence = com.auto_accent_and_check_accents(nom_sg, ap)
local ustem, _ = com.split_stem_desinence(unom_sg)
local num = {}
if not args.n or not rfind(args.n, "^s?d?p?$") then
error("Illegal number “" .. args.n .. "”. Possible values are “s”, “d”, “p”, “sd”, “dp”, “sp”, or “sdp”.")
else
num = rsplit(args.n, "")
end
if (nom_sg == "" or desinence == "") then
error("Error: SUBPAGENAME=" .. SUBPAGENAME .. "Must only be used in the Reconstruction namespace with " .. lang:getCanonicalName() .. " reconstructions")
end
local stem_type = get_stem(args["stem"], desinence, gender, unom_sg)
if stem_type == "soft a-stem" and desinence=="i" then -- ī-stem +j/+ьj (Module:sla-noun/data declensions["soft a-stem"] doesn't let check data.args["stem"], for some reason #data.args==0)
stem = ( args["stem"] and args["stem"]=="ī/ьj" and ustem.."ьj" or com.iotate(ustem) )
end
if ap and ap ~= "a" and ap ~= "b" and ap ~= "c" then
error("Accent paradigm “" .. ap .. "” must be either “a”, “b”, or “c”")
end
local forms, title, extracats
local categories = {}
local data = {
args = args,
gender = gender,
desinence = desinence,
ap = ap,
nom_sg = nom_sg,
unom_sg = unom_sg, -- only used for *mati/*dъťi?
stem = stem,
ustem = ustem,
footnotes = {},
footnote_to_sym = {},
next_notesym = "*"
}
local declensions = require("Module:sla-noun/data")
if declensions[stem_type] then
forms, title, extracats = declensions[stem_type](data)
else
error("Internal error -- unrecognized internal stem type '" .. stem_type .. "'")
end
if extracats then
for _, cat in ipairs(extracats) do
-- table.insert(categories, lang:getCanonicalName() .. " " .. cat)
end
end
-- table.insert(categories, 1, lang:getCanonicalName() .. " " .. title .. " nouns")
if ap then
title = title .. ", accent paradigm " .. ap
-- table.insert(categories, lang:getCanonicalName() .. " nominals with accent paradigm " .. ap)
end
if #num == 1 then
if num[1] == 's' then
title = title .. ', uncountable'
-- table.insert(categories, lang:getCanonicalName() .. " singularia tantum")
elseif num[1] == 'p' then
title = title .. ', plural only'
-- table.insert(categories, lang:getCanonicalName() .. " pluralia tantum")
end
end
return make_table(forms, num, title, data.footnotes) .. m_utilities.format_categories(categories, lang)
end
function get_stem(st, desinence, gender, unom_sg)
if st then -- explicitly specified stem
if st == "o" then
if "ъ" == desinence then
return "hard masculine o-stem"
elseif "ь" == desinence then
return "soft masculine o-stem"
elseif "o" == desinence then
return "hard neuter o-stem"
elseif "e" == desinence then
return "soft neuter o-stem"
else
error("Unrecognized ending for o-stem")
end
elseif st == "a" then
if "a" ~= desinence then
error("Unrecognized ending for a-stem")
end
if rfind(unom_sg, "[cčďjľňřšťž]a$") or rfind(unom_sg, "dza$") then
return "soft a-stem"
else
return "hard a-stem"
end
elseif st == "i" then
if "ь" ~= desinence then
error("Unrecognized ending for i-stem")
end
if gender == "m" then
return "တံမအရေဝ် (-ိ/i)ပုလ္လိၚ်"
elseif gender == "f" then
return "တံမအရေဝ် (-ိ/i)ဣတ္တိလိၚ်"
else
error("Gender for i-stems must be specified through g= parameter, as \"m\" or \"f\"")
end
elseif st == "ī" or st=="ī/ьj" or st=="ī/j" then
if "i" ~= desinence then
error("Unrecognized ending for ī-stem")
end
return "soft a-stem" -- FIXME, remove this hack
--consonant stems have several names in the literature, we handle all so that editors don't have to remember which one Wiktionary prefers
elseif st == "n" then
return "n-stem"
elseif st == "nt" or st == "t" then
return "nt-stem"
elseif st == "r" then
return "r-stem"
elseif st == "s" then
return "s-stem"
elseif st == "u" then
return "u-stem"
elseif st == "v" or st == "ū" or st == "ъv" then
return "v-stem"
else
error("Unrecognized stem class " .. st)
end
-- Autodetect common stem types on the basis of desinence, preceding
-- consonant, and passed arguments (g=).
-- hard masculine o-stems always and in -ъ, and we skip u-stems (which have stem= parameter provided)
elseif "ъ" == desinence then
return "hard masculine o-stem"
-- soft masculine o-stems end in ь and are preceded by a soft, palatal consonant, except for such i-stems which will
-- always have g= parameter specified
elseif "ь" == desinence and not gender and (rfind(unom_sg, "[cčďjľňřšťž]ь$") or rfind(unom_sg, "dzь$")) then
return "soft masculine o-stem"
-- hard neuter o-stems always end in -o, and we skip s-stems in -o (which have stem= parameter provided)
elseif "o" == desinence then
return "hard neuter o-stem"
-- soft neuter o-stems always end in -e and are preceded by a soft, platal consonant, and we skip s-stems in -e
-- (which have stem= parameter provided)
elseif "e" == desinence and rfind(unom_sg, "[cčďjľňřšťž]e$") then
return "soft neuter o-stem"
-- soft a-stems are feminines and masculines (OCS junoša) that and in -a and are preceded by a soft, palatal consonant, or
-- in -i (except for words *mati and *dъťi which are handled as r-stems)
elseif ( "a" == desinence and ( rfind(unom_sg, "[cčďjľňřšťž]a$") or rfind(unom_sg, "dza$") ) )
or
( ("i" == desinence) and (unom_sg ~= "mati") and (unom_sg ~= "dъťi") ) then
return "soft a-stem"
-- hard a-stems are the ones that are not soft a-stems
elseif "a" == desinence then
return "hard a-stem"
-- i-stems ending in -ь preceded by a hard, non-palatal consonant. Gender is mandatory to distinguish between masculine and
-- feminine inflection. We skip n-stems (having stem= parameter specified), which are handled below.
elseif "ь" == desinence then
if gender == "m" then
return "တံမအရေဝ် (-ိ/i)ပုလ္လိၚ်"
elseif gender == "f" then
return "တံမအရေဝ် (-ိ/i)ဣတ္တိလိၚ်"
else
error("Gender for i-stems must be specified through g= parameter, as “m” or “f”")
end
-- in case of r-stems, there are only two nouns, so the stem= parameter might as well be superfluous
elseif (unom_sg == "mati") or (unom_sg == "dъťi") then
return "r-stem"
else
error("Unable to autodetect stem type; must specify stem=, per [[WT:ASLA]]")
end
end
local number_map = {
s = "ကိုန်ဨကဝုစ်",
d = "ၜါလ္ပာ်",
p = "ကိုန်ဗဟုဝစ်",
}
local case_map = {
nom = "'''ပရေၚ်ပ္တိုန်စရၚ်ယၟု'''",
acc = "'''ကမ္မကာရက'''",
gen = "'''ဗဳဇဂကူ'''",
loc = "'''ခၞံဗဒှ်ဌာန်မတန်တဴ'''",
dat = "'''ပြကမ္မကာရက'''",
ins = "'''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်'''",
voc = "'''ပရေၚ်ဂယိုၚ်လမျီု'''",
}
function make_header(forms, num, title)
local frame = mw.getCurrentFrame()
local lemma = forms.nom[num[1]]
if type(lemma) ~= "table" then
-- lemma remains
elseif lemma.notesym then
lemma = lemma[1]
else
local lemmavals = {}
for _, item in ipairs(lemma) do
if type(item) == "table" then
table.insert(lemmavals, com.link_form(item[1]))
else
table.insert(lemmavals, com.link_form(item))
end
end
lemma = table.concat(lemmavals, ", ")
end
local header = { frame:expandTemplate{
title = 'inflection-table-top',
args = {
title = '[[Template:sla-decl-noun|မလဟုတ်စှ်ေ]]ဆေၚ်စပ်ကဵု ' .. lemma .. (title and " (" .. title .. ")" or "") .. '',
palette = 'blue',
tall = 'yes',
}
} ..
'|-',
'! ',
}
for _, n in ipairs(num) do
table.insert(header, '! ' .. number_map[n])
end
return table.concat(header, "\n")
end
function make_row(forms, num, case)
local row = {
"|-",
"! " .. case_map[case] .. ""
}
for _, n in ipairs(num) do
table.insert(row, "| " .. com.link_form(forms[case][n]))
end
return table.concat(row, "\n")
end
function make_footer(footnotes)
local frame = mw.getCurrentFrame()
local footnote_text = (#footnotes > 0) and table.concat(footnotes, "<br />") or ""
return frame:expandTemplate{
title = 'inflection-table-bottom',
args = {
notes = footnote_text,
}
}
end
-- Make the table
function make_table(forms, num, title, footnotes)
return table.concat(
{
make_header(forms, num, title),
make_row(forms, num, "nom"),
make_row(forms, num, "gen"),
make_row(forms, num, "dat"),
make_row(forms, num, "acc"),
make_row(forms, num, "ins"),
make_row(forms, num, "loc"),
make_row(forms, num, "voc"),
make_footer(footnotes),
},
"\n"
)
end
return export
cdzl5ltinl7yb34vud1omgsbp0jdbez
မဝ်ဂျူ:sla-noun/documentation
828
297536
399826
2026-07-21T08:15:40Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module is used to create declensional tables for Proto-Slavic nouns. <includeonly> {{module cat|sla-pro}} </includeonly>"
399826
wikitext
text/x-wiki
This module is used to create declensional tables for Proto-Slavic nouns.
<includeonly>
{{module cat|sla-pro}}
</includeonly>
s83z5z3n7zr0i6kmafufibdeplkk0z7
399827
399826
2026-07-21T08:16:04Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:sla-noun/doc]] ဇရေင် [[မဝ်ဂျူ:sla-noun/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399826
wikitext
text/x-wiki
This module is used to create declensional tables for Proto-Slavic nouns.
<includeonly>
{{module cat|sla-pro}}
</includeonly>
s83z5z3n7zr0i6kmafufibdeplkk0z7
ကဏ္ဍ:မဝ်ဂျူသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်
14
297537
399828
2026-07-21T08:17:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသလာဗေတ်-အခိုက်ကၞာ|သလာဗေတ်..."
399828
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလာဗေတ်-အခိုက်ကၞာ|သလာဗေတ်-အခိုက်ကၞာ]] » '''မဝ်ဂျူဂမၠိုၚ်'''
:[[:ကဏ္ဍ:မဝ်ဂျူဂမၠိုၚ်|မဝ်ဂျူ]]ဘာသာသလာဗေတ်-အခိုက်ကၞာ၊ မနွံကဵုလုပ်အဝေါၚ်ကုဒ် Lua နကဵုမကၠောန်ဗဒှ် ကဵု မစဳရေၚ်ယဵုဒုၚ်သ္ပမာန်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာသလာဗေတ်-အခိုက်ကၞာ]][[ကဏ္ဍ:မဝ်ဂျူဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
mnpzcjx75kl33rodfe4cc99w7ndbr8m
ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်
14
297538
399829
2026-07-21T08:19:18Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]]ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ..."
399829
wikitext
text/x-wiki
[[ကဏ္ဍ:မဝ်ဂျူသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
eoi2r4213mbiuujf9lec8jacf9mmnsc
မဝ်ဂျူ:sla-common/documentation
828
297539
399832
2026-07-21T08:27:43Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module contains common helper functions for Proto-Slavic, that are needed by other modules. <includeonly> {{module cat|sla-pro}} </includeonly>"
399832
wikitext
text/x-wiki
This module contains common helper functions for Proto-Slavic, that are needed by other modules.
<includeonly>
{{module cat|sla-pro}}
</includeonly>
oxpp2mcmv2jpx8s9yzmlhkilfz2e8pi
399833
399832
2026-07-21T08:28:22Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:sla-common/doc]] ဇရေင် [[မဝ်ဂျူ:sla-common/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399832
wikitext
text/x-wiki
This module contains common helper functions for Proto-Slavic, that are needed by other modules.
<includeonly>
{{module cat|sla-pro}}
</includeonly>
oxpp2mcmv2jpx8s9yzmlhkilfz2e8pi
မဝ်ဂျူ:sla-noun/data
828
297540
399834
2026-07-21T08:30:03Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "local declensions = {} local com = require("Module:sla-common") local m_table_tools = require("Module:table tools") local lang = require("Module:languages").getByCode("sla-pro") local u = mw.ustring.char local rfind = mw.ustring.find local rsubn = mw.ustring.gsub local rmatch = mw.ustring.match local rsplit = mw.text.split local ulower = mw.ustring.lower local uupper = mw.ustring.upper local usub = mw.ustring.sub lo..."
399834
Scribunto
text/plain
local declensions = {}
local com = require("Module:sla-common")
local m_table_tools = require("Module:table tools")
local lang = require("Module:languages").getByCode("sla-pro")
local u = mw.ustring.char
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local uupper = mw.ustring.upper
local usub = mw.ustring.sub
local ulen = mw.ustring.len
local ugmatch = mw.ustring.gmatch
local GRAVE = u(0x0300) -- grave = ̀
local TILDE = u(0x0303) -- tilde = ̃
local INVBREVE = u(0x0311) -- inverse breve = ̑
local MACRON = u(0x0304) -- macron = ̄
local UNK = "-" -- unknown accent (placeholder; existing accents removed)
local LEAVE = nil -- leave the accent alone
local contract_across_j_note = "The second form occurs in languages that contract early across /j/ (e.g. Czech), while the first form occurs in languages that do not (e.g. Russian)."
local a_stem_loc_pl_note = "''-asъ'' is the expected Balto-Slavic form but is found only in some Old Czech documents; ''-axъ'' is found everywhere else and is formed by analogy with other locative plurals in ''-xъ''."
local hard_o_stem_ins_sg_note = "''-ъmь'' in North Slavic, ''-omь'' in South Slavic."
local soft_o_stem_ins_sg_note = "''-ьmь'' in North Slavic, ''-emь'' in South Slavic."
local cons_stem_alt_pl_note = "''-ьmъ''/etc. are the original consonant-stem endings, while ''-amъ''/etc. are later Common Slavic endings formed by analogy with a-stems."
local function combine_stem_ending(stem, endinfo)
if endinfo.override then
return endinfo.override
end
local accent = endinfo[1]
local ending = endinfo[2]
if endinfo.pal1 then
stem = com.first_palatalization(stem)
elseif endinfo.pal2 then
stem = com.second_palatalization(stem)
elseif endinfo.iotate then
stem = com.iotate(stem)
end
if accent then
stem = com.set_accent(stem, accent)
end
return stem .. ending
end
local next_notesym_table = {
["*"]="**",
["**"]="***",
["***"]="†",
["†"]="††",
["††"]="†††",
["†††"]="‡",
["‡"]="‡‡",
["‡‡"]="‡‡",
["‡‡‡"]="1"
}
local function get_next_notesym(sym)
return next_notesym_table[sym] or sym + 1
end
-- Value is either a single string (substitute that exact string),
-- an "ending table" or a list of ending tables. An ending table is
-- a table of one item (a string, substitute that exact string) or
-- two items (the accent to apply to the stem, and the ending).
-- Either form can have optional named values attached. In both
-- forms, 'footnote' can be used to specify a footnote; in the
-- two-item form, 'pal1', 'pal2', and 'iotate' can additionally be
-- given to cause the appropriate modification to the end of the
-- stem.
local function add_form(data, stem, endinfo)
if type(endinfo) ~= "table" then
endinfo = {endinfo}
end
if type(endinfo[1]) ~= "table" then
endinfo = {endinfo}
end
local retval = {}
for _, endi in ipairs(endinfo) do
local form
if endi[2] then
form = combine_stem_ending(stem, endi)
else
form = endi[1]
end
if endi.footnote then
local notesym = data.footnote_to_sym[endi.footnote]
if not notesym then
notesym = data.next_notesym
data.next_notesym = get_next_notesym(notesym)
data.footnote_to_sym[endi.footnote] = notesym
table.insert(data.footnotes, m_table_tools.superscript_notes(notesym) .. " " .. endi.footnote)
end
table.insert(retval, {form, notesym=notesym})
else
table.insert(retval, form)
end
end
return retval
end
-- Add a full set of forms to the forms in FORMS for a given stem and the
-- ending specs for all endings. The value of SG, DU and PL is a table of
-- ending specs, containing entries for individual cases (n=nominative,
-- a=accusative, g=genitive, l=locative, d=dative, i=instrumental, v=vocative).
-- All seven values should be provided for the singular; all but vocative
-- should be provided for the plural (vocative plural is always the same as
-- nominative plural); for the dual, only nominative, genitive and dative
-- should be provided (accusative and vocative are the same as nominative,
-- locative is the same as genitive, and instrumental is the same as dative).
--
-- Each ending spec is either a string (use that exact string for the entire
-- case form) or a table SPEC indicating how to construct the case form, or
-- a list of such table SPECS if there are multiple possibilities. SPEC should
-- be either a list containing a single string (use that exact string for the
-- entire case form), or a list containing two strings and optional additional
-- flags. In the latter case, where SPEC[1] is the accent to place on the
-- stem (or an empty string to remove any stressed accent but leave macrons,
-- or the value UNK [for "unknown"] to remove all accents, or the value
-- LEAVE to leave any existing accents), SPEC[2] is the ending to add to the
-- stem, optional SPEC.pal1 causes the stem to have the first palatalization
-- applied, optional SPEC.pal2 causes the stem to have the second palatalization
-- applied, optional SPEC.iotate causes the stem to have iotation applied.
local function add_forms(data, forms, stem, sg, du, pl)
forms.nom = {
s = add_form(data, stem, sg.n),
d = add_form(data, stem, du.n),
p = add_form(data, stem, pl.n),
}
forms.acc = {
s = add_form(data, stem, sg.a),
d = forms.nom.d,
p = add_form(data, stem, pl.a),
}
forms.gen = {
s = add_form(data, stem, sg.g),
d = add_form(data, stem, du.g),
p = add_form(data, stem, pl.g),
}
forms.loc = {
s = add_form(data, stem, sg.l),
d = forms.gen.d,
p = add_form(data, stem, pl.l),
}
forms.dat = {
s = add_form(data, stem, sg.d),
d = add_form(data, stem, du.d),
p = add_form(data, stem, pl.d),
}
forms.ins = {
s = add_form(data, stem, sg.i),
d = forms.dat.d,
p = add_form(data, stem, pl.i),
}
forms.voc = {
s = add_form(data, stem, sg.v),
d = forms.nom.d,
p = forms.nom.p,
}
end
-- All consonant stems (ū, r, masc/neut n, s, nt) behave very similarly so
-- we merge their functionality. All such stems have an infix composed of
-- a vowel (V) + a consonant (C), which occurs between the stem and ending in
-- all cases but the nominative/vocative (and accusative singular of neuters).
-- DOPAL should be true if the stem should be first-palatalized before the
-- infix, and ALTFEMPL is true if alternative endings in -am* should be given
-- as well (used for v-stems).
local function handle_consonant_stem(data, v, c, g, dopal, altfempl)
local forms = {}
local palstem = dopal and com.first_palatalization(data.stem) or data.stem
local nonsyll = com.is_nonsyllabic(palstem)
local ap = data.ap
-- FIXME! Don't know the actual accents of *dьnь (pattern c),
-- so treat as if unknown.
if nonsyll and g == "m" then
ap = nil
end
if ap == "a" or ap == "b" then
add_forms(data, forms, palstem .. v .. (data.ap == "b" and GRAVE or "") .. c,
-- FIXME! Need to check voc, need accents for dual
-- FIXME! Formerly had ьmi for inst pl of all genders
{n=data.nom_sg, a=g == "n" and data.nom_sg or {GRAVE, "ь"}, g={GRAVE, "e"}, l={GRAVE, "e"}, d={GRAVE, "i"}, i=g == "f" and {{GRAVE, "ьjǫ"}, {GRAVE, "ǭ", iotate=true, footnote=contract_across_j_note}} or {GRAVE, "ьmь"}, v=data.nom_sg},
{n={GRAVE, "i"}, g={GRAVE, "u"},
d=altfempl and {{GRAVE, "ьma"}, {GRAVE, "ama", footnote=cons_stem_alt_pl_note}} or {GRAVE, "ьma"}},
{n={GRAVE, g == "m" and "e" or g == "f" and "i" or "ā"}, a={GRAVE, g == "n" and "ā" or "i"}, g={GRAVE, "ъ"},
l=altfempl and {{GRAVE, "ьxъ"}, {GRAVE, "axъ", footnote=cons_stem_alt_pl_note}} or {GRAVE, "ьxъ"},
d=altfempl and {{GRAVE, "ьmъ"}, {GRAVE, "amъ", footnote=cons_stem_alt_pl_note}} or {GRAVE, "ьmъ"},
i=altfempl and {{GRAVE, "ьmī"}, {GRAVE, "amī", footnote=cons_stem_alt_pl_note}} or {GRAVE, g == "n" and "ȳ" or "ьmī"}
}
)
elseif ap == "c" then
local ldac = nonsyll and INVBREVE or TILDE
add_forms(data, forms, palstem .. v .. c,
-- FIXME! Need to check voc
-- FIXME! Formerly had ьmi for inst pl of all genders
{n=data.nom_sg, a=g == "n" and data.nom_sg or {INVBREVE, "ь"}, g={INVBREVE, "e"}, l={INVBREVE, "e"}, d={INVBREVE, "i"}, i=g == "f" and {"", "ьjǫ́"} or {INVBREVE, "ьmь"}, v=data.nom_sg},
{n={INVBREVE, "i"}, g={"", "ù"},
d=altfempl and {{"", "ьmà"}, {"", "àma", footnote=cons_stem_alt_pl_note}} or {"", "ьmà"}},
{n=g == "n" and {"", "à"} or g == "m" and {INVBREVE, "e"} or {INVBREVE, "i"}, a=g == "n" and {"", "à"} or {INVBREVE, "i"}, g={TILDE, "ъ"},
l=altfempl and {{ldac, "ьxъ"}, {ldac, "axъ", footnote=cons_stem_alt_pl_note}} or {ldac, "ьxъ"},
d=altfempl and {{ldac, "ьmъ"}, {ldac, "amъ", footnote=cons_stem_alt_pl_note}} or {ldac, "ьmъ"},
i=altfempl and {{"", "ьmì"}, {"", "amì", footnote=cons_stem_alt_pl_note}} or {"", g == "n" and "ý" or "ьmì"}
}
)
else
add_forms(data, forms, palstem .. v .. c,
-- FIXME! Need to check voc, need accents for dual
-- FIXME! Formerly had ьmi for inst pl of all genders
{n=data.nom_sg, a=g == "n" and data.nom_sg or {UNK, "ь"}, g={UNK, "e"}, l={UNK, "e"}, d={UNK, "i"}, i=g == "f" and {{UNK, "ьjǫ"}, {UNK, "ǫ", iotate=true, footnote=contract_across_j_note}} or {UNK, "ьmь"}, v=nonsyll and g == "m" and {UNK, "y"} or data.nom_sg},
{n={UNK, "i"}, g={UNK, "u"},
d=altfempl and {{UNK, "ьma"}, {UNK, "ama", footnote=cons_stem_alt_pl_note}} or {UNK, "ьma"}},
{n={UNK, g == "m" and "e" or g == "f" and "i" or "a"}, a={UNK, g == "n" and "a" or "i"}, g={UNK, "ъ"},
l=altfempl and {{UNK, "ьxъ"}, {UNK, "axъ", footnote=cons_stem_alt_pl_note}} or {UNK, "ьxъ"},
d=altfempl and {{UNK, "ьmъ"}, {UNK, "amъ", footnote=cons_stem_alt_pl_note}} or {UNK, "ьmъ"},
i=altfempl and {{UNK, "ьmi"}, {UNK, "ami", footnote=cons_stem_alt_pl_note}} or {UNK, g == "n" and "y" or "ьmi"}
}
)
end
return forms
end
declensions["v-stem"] = function(data)
local forms
local y_type = data.desinence == "y"
local i_type = data.desinence == "i"
if not(y_type or i_type) then
error("v-stem nouns must end in -y or -i")
end
if i_type then
forms = handle_consonant_stem(data, "ь", "v", "f", false, "altfempl")
else
forms = handle_consonant_stem(data, "ъ", "v", "f", false, "altfempl")
end
if i_type then
return forms, "soft v-stem"
else
return forms, "hard v-stem"
end
end
declensions["s-stem"] = function(data)
if data.desinence ~= "e" and data.desinence ~= "o" then
error("s-stem nouns must end in -e or -o")
end
return handle_consonant_stem(data, "e", "s", "n", "palatalize"), "s-stem"
end
declensions["r-stem"] = function(data)
if (data.unom_sg ~= "mati") and (data.unom_sg ~= "dъťi") then
error("Must be used only for nouns *mati and *dъťi")
end
return handle_consonant_stem(data, "e", "r", "f", "palatalize"), "r-stem"
end
declensions["nt-stem"] = function(data)
if data.desinence ~= "ę" then
error("nt-stem nouns must end in -ę")
end
return handle_consonant_stem(data, "ę", "t", "n", "palatalize"), "nt-stem"
end
declensions["n-stem"] = function(data)
local forms
-- masculine nouns have desinence end in -nь or -y, neuters in -ę
local y_type = data.desinence == "y"
local ni_type = data.desinence == "ь"
local e_type = data.desinence == "ę"
if not(y_type or ni_type or e_type) then
error("Wrong ending for an n-stem noun")
end
if ni_type then
if data.ustem ~= "dьn" then
error("n-stem noun ending in -ь must be *dьnь")
end
data.stem = "d"
data.ustem = "d"
forms = handle_consonant_stem(data, "", "", "m", "palatalize")
else
forms = handle_consonant_stem(data, "e", "n", y_type and "m" or "n", "palatalize")
end
return forms, "n-stem", e_type and {"neuter n-stem nouns"} or {"masculine n-stem nouns"}
end
-- Masculine and feminine i-stems differ only in the instrumental singular and
-- nominative plural so handle them together.
local function handle_i_stem(data, masc)
local forms = {}
if data.ap == "a" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc, dual
{n=data.nom_sg, a=data.nom_sg, g={GRAVE, "ī"}, l={GRAVE, "ī"}, d={GRAVE, "i"}, i=masc and {GRAVE, "ьmь"} or {{GRAVE, "ьjǫ"}, {GRAVE, "ǭ", iotate=true, footnote=contract_across_j_note}}, v={UNK, "i"}},
{n={GRAVE, "i"}, g={{GRAVE, "ьju"}, {GRAVE, "u", iotate=true, footnote=contract_across_j_note}}, d={GRAVE, "ьma"}},
{n=masc and {{GRAVE, "ьjē"}, {GRAVE, "ē", iotate=true, footnote=contract_across_j_note}} or {GRAVE, "i"}, a={GRAVE, "i"}, g={{GRAVE, "ьjь"}, {GRAVE, "ī", footnote=contract_across_j_note}}, l={GRAVE, "ьxъ"}, d={GRAVE, "ьmъ"}, i={GRAVE, "ьmī"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc, dual
{n={TILDE, "ь"}, a={TILDE, "ь"}, g={TILDE, "i"}, l={TILDE, "i"}, d={MACRON, "ì"}, i=masc and {MACRON, "ь̀mь"} or {{TILDE, "ьjǫ"}, {TILDE, "ǫ", iotate=true, footnote=contract_across_j_note}}, v={UNK, "i"}},
{n={MACRON, "ì"}, g={{TILDE, "ьju"}, {UNK, "u", iotate=true, footnote=contract_across_j_note}}, d={TILDE, "ьma"}},
{n=masc and {{TILDE, "ьjē"}, {TILDE, "ē", iotate=true, footnote=contract_across_j_note}} or {MACRON, "ì"}, a={MACRON, "ì"}, g={{MACRON, "ь̀jь"}, {TILDE, "i", footnote=contract_across_j_note}}, l={MACRON, "ь̀xъ"}, d={MACRON, "ь̀mъ"}, i={TILDE, "ьmī"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={INVBREVE, "ь"}, a={INVBREVE, "ь"}, g={"", "í"}, l={"", "í"}, d={INVBREVE, "i"}, i=masc and {INVBREVE, "ьmь"} or {"", "ьjǫ́"}, v={UNK, "i"}},
{n={INVBREVE, "i"}, g={{"", "ьjù"}, {UNK, "u", iotate=true, footnote=contract_across_j_note}}, d={"", "ьmà"}},
{n=masc and {{INVBREVE, "ьjē"}, {INVBREVE, "ē", iotate=true, footnote=contract_across_j_note}} or {INVBREVE, "i"}, a={INVBREVE, "i"}, g={"", "ь̀jь"}, l={INVBREVE, "ьxъ"}, d={INVBREVE, "ьmъ"}, i={"", "ьmì"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "i"}, l={UNK, "i"}, d={UNK, "i"}, i=masc and {UNK, "ьmь"} or {{UNK, "ьjǫ"}, {UNK, "ǫ", iotate=true, footnote=contract_across_j_note}}, v={UNK, "i"}},
{n={UNK, "i"}, g={{UNK, "ьju"}, {UNK, "u", iotate=true, footnote=contract_across_j_note}}, d={UNK, "ьma"}},
{n=masc and {{UNK, "ьje"}, {UNK, "e", iotate=true, footnote=contract_across_j_note}} or {UNK, "i"}, a={UNK, "i"}, g={{UNK, "ьjь"}, {UNK, "i", footnote=contract_across_j_note}}, l={UNK, "ьxъ"}, d={UNK, "ьmъ"}, i={UNK, "ьmi"}}
)
end
return forms, "i-stem", masc and {"masculine i-stem nouns"} or {"feminine i-stem nouns"}
end
declensions["feminine i-stem"] = function(data)
return handle_i_stem(data, false)
end
declensions["masculine i-stem"] = function(data)
return handle_i_stem(data, "masc")
end
declensions["u-stem"] = function(data)
local forms = {}
if data.desinence ~= "ъ" then
error("u-stem nouns must end in -ъ")
end
if data.ap == "a" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc, dual
{n=data.nom_sg, a=data.nom_sg, g={GRAVE, "u"}, l={GRAVE, "ū"}, d={GRAVE, "ovi"}, i={GRAVE, "ъmь"}, v={GRAVE, "u"}},
{n={GRAVE, "y"}, g={GRAVE, "ovu"}, d={GRAVE, "ъma"}},
{n={GRAVE, "ove"}, a={GRAVE, "y"}, g={GRAVE, "ovъ"}, l={GRAVE, "ъxъ"}, d={GRAVE, "ъmъ"}, i={GRAVE, "ъmī"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={TILDE, "ъ"}, a={TILDE, "ъ"}, g={MACRON, "ù"}, l={TILDE, "u"}, d={MACRON, "òvi"}, i={MACRON, "ъ̀mь"}, v={UNK, "u"}},
{n={MACRON, "ỳ"}, g={MACRON, "òvu"}, d={TILDE, "ъma"}},
{n={MACRON, "òve"}, a={MACRON, "ỳ"}, g={MACRON, "òvъ"}, l={MACRON, "ъ̀xъ"}, d={MACRON, "ъ̀mъ"}, i={TILDE, "ъmī"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={INVBREVE, "ъ"}, a={INVBREVE, "ъ"}, g={INVBREVE, "u"}, l={"", "ú"}, d={INVBREVE, "ovi"}, i={INVBREVE, "ъmь"}, v={UNK, "u"}},
{n={INVBREVE, "y"}, g={"", "ovù"}, d={"", "ъmà"}},
{n={INVBREVE, "ove"}, a={INVBREVE, "y"}, g={"", "òvъ"}, l={INVBREVE, "ъxъ"}, d={INVBREVE, "ъmъ"}, i={"", "ъmì"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "u"}, l={UNK, "u"}, d={UNK, "ovi"}, i={UNK, "ъmь"}, v={UNK, "u"}},
{n={UNK, "y"}, g={UNK, "ovu"}, d={UNK, "ъma"}},
{n={UNK, "ove"}, a={UNK, "y"}, g={UNK, "ovъ"}, l={UNK, "ъxъ"}, d={UNK, "ъmъ"}, i={UNK, "ъmi"}}
)
end
return forms, "u-stem"
end
declensions["hard a-stem"] = function(data)
local forms = {}
if data.ap == "a" then
add_forms(data, forms, data.stem,
{n=data.nom_sg, a={GRAVE, "ǫ"}, g={GRAVE, "y"}, l={GRAVE, "ě", pal2=true}, d={GRAVE, "ě", pal2=true}, i={{GRAVE, "ojǫ"}, {GRAVE, "ǭ", footnote=contract_across_j_note}}, v={GRAVE, "o"}},
{n={GRAVE, "ě", pal2=true}, g={GRAVE, "u"}, d={GRAVE, "ama"}},
{n={GRAVE, "y"}, a={GRAVE, "y"}, g={GRAVE, "ъ"}, l={{GRAVE, "asъ"}, {GRAVE, "axъ", footnote=a_stem_loc_pl_note}}, d={GRAVE, "amъ"}, i={GRAVE, "amī"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={MACRON, "à"}, a={MACRON, "ǫ̀"}, g={MACRON, "ỳ"}, l={MACRON, "ě̀", pal2=true}, d={MACRON, "ě̀", pal2=true}, i={{MACRON, "òjǫ"}, {TILDE, "ǫ", footnote=contract_across_j_note}}, v={UNK, "o"}},
{n={TILDE, "ě", pal2=true}, g={MACRON, "ù"}, d={MACRON, "àma"}},
{n={MACRON, "ỳ"}, a={MACRON, "ỳ"}, g={TILDE, "ъ"}, l={{MACRON, "àsъ"}, {MACRON, "àxъ", footnote=a_stem_loc_pl_note}}, d={MACRON, "àmъ"}, i={MACRON, "àmī"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={"", "à"}, a={INVBREVE, "ǫ"}, g={"", "ý"}, l={INVBREVE, "ě", pal2=true}, d={"", "ě̀", pal2=true}, i={"", "ojǫ́"}, v={UNK, "o"}},
{n={INVBREVE, "ě", pal2=true}, g={"", "ù"}, d={"", "àma"}},
{n={INVBREVE, "y"}, a={INVBREVE, "y"}, g={TILDE, "ъ"}, l={{"", "àsъ"}, {"", "àxъ", footnote=a_stem_loc_pl_note}}, d={"", "àmъ"}, i={"", "àmi"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a={UNK, "ǫ"}, g={UNK, "y"}, l={UNK, "ě", pal2=true}, d={UNK, "ě", pal2=true}, i={{UNK, "ojǫ"}, {UNK, "ǫ", footnote=contract_across_j_note}}, v={LEAVE, "o"}},
{n={UNK, "ě", pal2=true}, g={UNK, "u"}, d={UNK, "ama"}},
{n={UNK, "y"}, a={UNK, "y"}, g={UNK, "ъ"}, l={{UNK, "asъ"}, {UNK, "axъ", footnote=a_stem_loc_pl_note}}, d={UNK, "amъ"}, i={UNK, "ami"}}
)
end
return forms, "hard a-stem"
end
declensions["soft a-stem"] = function(data)
local forms = {}
local stem = data.ustem
local title
-- ī-stems share the same endings as soft a-stems in all cases except for the nominative singular, so they are handled as a
-- special case of them.
-- for genuine ī-stems that are not preceded by a soft, palatal consonant (e.g. olni) we add "j" everywhere except in nom_sg
if data.desinence == "i" then
title = "ī-stem"
stem = com.iotate(stem)
else
if not rfind(stem, "[cčďjľňřšťž]$") and not rfind(stem, "dz$") then
error("Soft a-stem must end in a soft consonant (given: " .. stem .. ")")
end
title = "soft a-stem"
end
if data.ap == "a" then
add_forms(data, forms, data.stem,
{n=data.nom_sg, a={GRAVE, "ǫ"}, g={GRAVE, "ę̇"}, l={GRAVE, "ī"}, d={GRAVE, "ī"}, i={{GRAVE, "ējǫ"}, {GRAVE, "ǭ", footnote=contract_across_j_note}}, v={GRAVE, "e"}},
{n={GRAVE, "i"}, g={GRAVE, "u"}, d={GRAVE, "ama"}},
{n={GRAVE, "ę̇"}, a={GRAVE, "ę̇"}, g={GRAVE, "ь"}, l={GRAVE, "āsъ"}, d={GRAVE, "āmъ"}, i={GRAVE, "āmī"}}
)
elseif data.ap == "b" then
-- Some accent-b ja-stem nouns behave more like a-stem nouns (e.g.
-- *svě̄ťà), while others take the standard form with neoacute accent
-- (vòlja). Remember that data.nom_sg and data.stem are decomposed.
if rfind(data.nom_sg, "a" .. GRAVE .. "$") then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={MACRON, "à"}, a={MACRON, "ǫ̀"}, g={MACRON, "ę̇̀"}, l={MACRON, "ì"}, d={MACRON, "ì"}, i={{MACRON, "èjǫ"}, {TILDE, "ǫ", footnote=contract_across_j_note}}, v={UNK, "e"}},
{n={TILDE, "i"}, g={MACRON, "ù"}, d={MACRON, "àma"}},
{n={MACRON, "ę̇̀"}, a={MACRON, "ę̇̀"}, g={TILDE, "ь"}, l={{MACRON, "àsъ"}, {MACRON, "àxъ", footnote=a_stem_loc_pl_note}}, d={MACRON, "àmъ"}, i={MACRON, "àmī"}}
)
else
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={TILDE, "a"}, a={TILDE, "ǫ"}, g={TILDE, "ę̇"}, l={TILDE, "i"}, d={TILDE, "i"}, i={{TILDE, "ejǫ"}, {TILDE, "ǫ", footnote=contract_across_j_note}}, v={UNK, "e"}},
{n={TILDE, "i"}, g={TILDE, "u"}, d={TILDE, "ama"}},
{n={TILDE, "ę̇"}, a={TILDE, "ę̇"}, g={TILDE, "ь"}, l={{TILDE, "asъ"}, {TILDE, "axъ", footnote=a_stem_loc_pl_note}}, d={TILDE, "amъ"}, i={TILDE, "amī"}}
)
end
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for voc
{n={"", "à"}, a={INVBREVE, "ǫ"}, g={"", "ę̇́"}, l={INVBREVE, "ī"}, d={"", "ì"}, i={"", "ejǫ́"}, v={UNK, "e"}},
{n={INVBREVE, "i"}, g={"", "ù"}, d={"", "àma"}},
{n={INVBREVE, "ę̇"}, a={INVBREVE, "ę̇"}, g={TILDE, "ь"}, l={{"", "àsъ"}, {"", "àxъ", footnote=a_stem_loc_pl_note}}, d={"", "àmъ"}, i={"", "àmi"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a={UNK, "ǫ"}, g={UNK, "ę̇"}, l={UNK, "i"}, d={UNK, "i"}, i={{UNK, "ejǫ"}, {UNK, "ǫ", footnote=contract_across_j_note}}, v={LEAVE, "e"}},
{n={UNK, "i"}, g={UNK, "u"}, d={UNK, "ama"}},
{n={UNK, "ę̇"}, a={UNK, "ę̇"}, g={UNK, "ь"}, l={{UNK, "asъ"}, {UNK, "axъ", footnote=a_stem_loc_pl_note}}, d={UNK, "amъ"}, i={UNK, "ami"}}
)
end
return forms, title
end
declensions["soft neuter o-stem"] = function(data)
local forms = {}
-- FIXME! No forms given for ap=a in Verweij
if data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for dual
{n={MACRON, "è"}, a={MACRON, "è"}, g={MACRON, "à"}, l={MACRON, "ì"}, d={MACRON, "ù"}, i={{MACRON, "ь̀mь"}, {MACRON, "èmь", footnote=soft_o_stem_ins_sg_note}}, v={MACRON, "è"}},
{n={TILDE, "i"}, g={UNK, "u"}, d={UNK, "ema"}}, -- The plural has neoacute throughout. Does the dual have this also?
{n={TILDE, "a"}, a={TILDE, "a"}, g={TILDE, "ь"}, l={TILDE, "ixъ"}, d={TILDE, "emъ"}, i={TILDE, "i"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
{n={INVBREVE, "e"}, a={INVBREVE, "e"}, g={INVBREVE, "a"}, l={INVBREVE, "i"}, d={INVBREVE, "u"}, i={{INVBREVE, "ьmь"}, {INVBREVE, "emь", footnote=soft_o_stem_ins_sg_note}}, v={INVBREVE, "e"}},
{n={INVBREVE, "i"}, g={"", "ù"}, d={"", "emà"}},
{n={"", "à"}, a={"", "à"}, g={TILDE, "ь"}, l={"", "íxъ"}, d={"", "émъ"}, i={"", "í"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "a"}, l={UNK, "i"}, d={UNK, "u"}, i={{UNK, "ьmь"}, {UNK, "emь", footnote=soft_o_stem_ins_sg_note}}, v=data.nom_sg},
{n={UNK, "i"}, g={UNK, "u"}, d={UNK, "ema"}},
{n={UNK, "a"}, a={UNK, "a"}, g={UNK, "ь"}, l={UNK, "ixъ"}, d={UNK, "emъ"}, i={UNK, "i"}}
)
end
return forms, "soft o-stem", {"soft neuter o-stem nouns"}
end
declensions["hard neuter o-stem"] = function(data)
local forms = {}
if data.ap == "a" then
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={GRAVE, "a"}, l={GRAVE, "ě", pal2=true}, d={GRAVE, "u"}, i={{GRAVE, "ъmь"}, {GRAVE, "omь", footnote=hard_o_stem_ins_sg_note}}, v=data.nom_sg},
{n={GRAVE, "ě", pal2=true}, g={GRAVE, "u"}, d={GRAVE, "oma"}},
{n={GRAVE, "a"}, a={GRAVE, "a"}, g={GRAVE, "ъ"}, l={GRAVE, "ě̄xъ", pal2=true}, d={GRAVE, "omъ"}, i={GRAVE, "ȳ"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
{n={MACRON, "ò"}, a={MACRON, "ò"}, g={MACRON, "à"}, l={MACRON, "ě̀", pal2=true}, d={MACRON, "ù"}, i={{MACRON, "ъ̀mь"}, {MACRON, "òmь", footnote=hard_o_stem_ins_sg_note}}, v={MACRON, "ò"}},
{n={TILDE, "ě", pal2=true}, g={MACRON, "ù"}, d={MACRON, "òma"}},
{n={MACRON, "à"}, a={MACRON, "à"}, g={TILDE, "ъ"}, l={TILDE, "ěxъ", pal2=true}, d={MACRON, "òmъ"}, i={TILDE, "y"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
{n={INVBREVE, "o"}, a={INVBREVE, "o"}, g={INVBREVE, "a"}, l={INVBREVE, "ě", pal2=true}, d={INVBREVE, "u"}, i={{INVBREVE, "ъmь"}, {INVBREVE, "omь", footnote=hard_o_stem_ins_sg_note}}, v=data.nom_sg},
{n={INVBREVE, "ě", pal2=true}, g={"", "ù"}, d={"", "omà"}},
{n={"", "à"}, a={"", "à"}, g={TILDE, "ъ"}, l={"", "ě̃xъ", pal2=true}, d={"", "òmъ"}, i={"", "ý"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "a"}, l={UNK, "ě", pal2=true}, d={UNK, "u"}, i={{UNK, "ъmь"}, {UNK, "omь", footnote=hard_o_stem_ins_sg_note}}, v=data.nom_sg},
{n={UNK, "ě", pal2=true}, g={UNK, "u"}, d={UNK, "oma"}},
{n={UNK, "a"}, a={UNK, "a"}, g={UNK, "ъ"}, l={UNK, "ěxъ", pal2=true}, d={UNK, "omъ"}, i={UNK, "y"}}
)
end
return forms, "hard o-stem", {"hard neuter o-stem nouns"}
end
declensions["hard masculine o-stem"] = function(data)
local forms = {}
if data.ap == "a" then
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={GRAVE, "a"}, l={GRAVE, "ě", pal2=true}, d={GRAVE, "u"}, i={{GRAVE, "ъmь"}, {GRAVE, "omь", footnote=hard_o_stem_ins_sg_note}}, v={GRAVE, "e", pal1=true}},
{n={GRAVE, "a"}, g={GRAVE, "u"}, d={GRAVE, "oma"}},
{n={GRAVE, "i", pal2=true}, a={GRAVE, "y"}, g={GRAVE, "ъ"}, l={GRAVE, "ě̄xъ", pal2=true}, d={GRAVE, "omъ"}, i={GRAVE, "ȳ"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for vocative sg
{n={TILDE, "ъ"}, a={TILDE, "ъ"}, g={MACRON, "à"}, l={MACRON, "ě̀", pal2=true}, d={MACRON, "ù"}, i={{MACRON, "ъ̀mь"}, {MACRON, "òmь", footnote=hard_o_stem_ins_sg_note}}, v={UNK, "e", pal1=true}},
{n={MACRON, "à"}, g={MACRON, "ù"}, d={MACRON, "òma"}},
{n={MACRON, "ì", pal2=true}, a={MACRON, "ỳ"}, g={TILDE, "ъ"}, l={TILDE, "ěxъ", pal2=true}, d={MACRON, "òmъ"}, i={TILDE, "y"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for vocative sg
{n={INVBREVE, "ъ"}, a={INVBREVE, "ъ"}, g={INVBREVE, "a"}, l={INVBREVE, "ě", pal2=true}, d={INVBREVE, "u"}, i={{INVBREVE, "ъmь"}, {INVBREVE, "omь", footnote=hard_o_stem_ins_sg_note}}, v={UNK, "e", pal1=true}},
{n={INVBREVE, "a"}, g={"", "ù"}, d={"", "omà"}},
{n={INVBREVE, "i", pal2=true}, a={INVBREVE, "y"}, g={TILDE, "ъ"}, l={"", "ě̃xъ", pal2=true}, d={"", "òmъ"}, i={"", "ý"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "a"}, l={UNK, "ě", pal2=true}, d={UNK, "u"}, i={{UNK, "ъmь"}, {UNK, "omь", footnote=hard_o_stem_ins_sg_note}}, v={UNK, "e", pal1=true}},
{n={UNK, "a"}, g={UNK, "u"}, d={UNK, "oma"}},
{n={UNK, "i", pal2=true}, a={UNK, "y"}, g={UNK, "ъ"}, l={UNK, "ěxъ", pal2=true}, d={UNK, "omъ"}, i={UNK, "y"}}
)
end
return forms, "hard o-stem", {"hard masculine o-stem nouns"}
end
declensions["soft masculine o-stem"] = function(data)
local forms = {}
local voc_e = rfind(data.stem, "c$") or rfind(data.stem, "dz$") or
rfind(data.stem, "sc$") or rfind(data.stem, "zdz$")
if data.ap == "a" then
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={GRAVE, "a"}, l={GRAVE, "i"}, d={GRAVE, "u"}, i={{GRAVE, "ьmь"}, {GRAVE, "emь", footnote=soft_o_stem_ins_sg_note}}, v={GRAVE, voc_e and "e" or "u", pal1=true}},
{n={GRAVE, "a"}, g={GRAVE, "u"}, d={GRAVE, "ema"}},
{n={GRAVE, "i"}, a={GRAVE, "ę̇"}, g={GRAVE, "ь"}, l={GRAVE, "īxъ"}, d={GRAVE, "ēmъ"}, i={GRAVE, "ī"}}
)
elseif data.ap == "b" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for vocative sg
{n={TILDE, "ь"}, a={TILDE, "ь"}, g={MACRON, "à"}, l={MACRON, "ì"}, d={MACRON, "ù"}, i={{MACRON, "ь̀mь"}, {MACRON, "èmь", footnote=soft_o_stem_ins_sg_note}}, v={UNK, voc_e and "e" or "u", pal1=true}},
{n={MACRON, "à"}, g={MACRON, "ù"}, d={MACRON, "èma"}},
{n={MACRON, "ì"}, a={MACRON, "ę̇̀"}, g={TILDE, "ь"}, l={TILDE, "ixъ"}, d={TILDE, "emъ"}, i={TILDE, "i"}}
)
elseif data.ap == "c" then
add_forms(data, forms, data.stem,
-- FIXME! Need accents for vocative sg
{n={INVBREVE, "ь"}, a={INVBREVE, "ь"}, g={INVBREVE, "a"}, l={INVBREVE, "i"}, d={INVBREVE, "u"}, i={{INVBREVE, "ьmь"}, {INVBREVE, "emь", footnote=soft_o_stem_ins_sg_note}}, v={UNK, voc_e and "e" or "u", pal1=true}},
{n={INVBREVE, "a"}, g={"", "ù"}, d={"", "emà"}},
{n={INVBREVE, "i"}, a={INVBREVE, "ę̇"}, g={TILDE, "ь"}, l={"", "ĩxъ"}, d={"", "èmъ"}, i={"", "í"}}
)
else
add_forms(data, forms, data.stem,
{n=data.nom_sg, a=data.nom_sg, g={UNK, "a"}, l={UNK, "i"}, d={UNK, "u"}, i={{UNK, "ьmь"}, {UNK, "emь", footnote=soft_o_stem_ins_sg_note}}, v={UNK, voc_e and "e" or "u", pal1=true}},
{n={UNK, "a"}, g={UNK, "u"}, d={UNK, "ema"}},
{n={UNK, "i"}, a={UNK, "ę̇"}, g={UNK, "ь"}, l={UNK, "ixъ"}, d={UNK, "emъ"}, i={UNK, "i"}}
)
end
return forms, "soft o-stem", {"soft masculine o-stem nouns"}
end
return declensions
g7nqtsedaeeoypyic9cqpq3yh7r37g4
မဝ်ဂျူ:sla-noun/data/documentation
828
297541
399835
2026-07-21T10:00:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> {{module cat|sla-pro}} </includeonly>"
399835
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|sla-pro}}
</includeonly>
b9rtp2khxu6dikkvwdkqnlmzrpp7v1t
399836
399835
2026-07-21T10:00:45Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:sla-noun/data/doc]] ဇရေင် [[မဝ်ဂျူ:sla-noun/data/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399835
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|sla-pro}}
</includeonly>
b9rtp2khxu6dikkvwdkqnlmzrpp7v1t
ကဏ္ဍ:မဝ်ဂျူဒေတာသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်
14
297542
399837
2026-07-21T10:01:59Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်|စ]][[ကဏ္ဍ:မဝ်ဂျူစရၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]"
399837
wikitext
text/x-wiki
[[ကဏ္ဍ:မဝ်ဂျူသလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်|စ]][[ကဏ္ဍ:မဝ်ဂျူစရၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
g5v7imvaacufxqu8snhe9u9h0ot80is
ထာမ်ပလိက်:hrow/documentation
10
297543
399839
2026-07-21T10:08:17Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses templatestyles|hrow/styles.css}} [[File:Tekstaus_H.gif|128px|right]] [[File:Text_direction_TDright.svg|128px|thumb|right|Down rightwards|link=w:en:Template:Script directionality]] Makes N rows with items going H-direction in [[Template:hrow/styles.css|adjacent container]]. It doesn't require additional templates. ==Parameters== * {{temp|hrow}}: different-width columns * {{temp|bl}}..."
399839
wikitext
text/x-wiki
{{documentation subpage}}
{{uses templatestyles|hrow/styles.css}}
[[File:Tekstaus_H.gif|128px|right]]
[[File:Text_direction_TDright.svg|128px|thumb|right|Down rightwards|link=w:en:Template:Script directionality]]
Makes N rows with items going H-direction in [[Template:hrow/styles.css|adjacent container]]. It doesn't require additional templates.
==Parameters==
* {{temp|hrow}}: different-width columns
* {{temp|bl}} can be used to specify end of last column if list is not ended.
Optional parameter:
* {{para|1}} Number of rows (default: {{para|1|1}})
*: {{para|1|1}} makes columns from every item (useful for multi-level lists if there are 2-5 top-level elements)
==Examples==
<pre>
{{hrow}}
* East Slavic:
** {{desc|orv|толокъно}}
*** {{desc|be|талакно́}}
*** {{desc|ru|толокно́}}
*** {{desc|uk|толокно́}}
** {{desc|bor=1|fi|talkkuna}}
* South Slavic:
** Slovene:
*** {{desc|bor=1|de|Dalken}}
** {{desc|bor=1|gmh|Talken}}
* West Slavic:
** {{desc|pl|tłukno}}
</pre>
{{hrow}}
* East Slavic:
** {{desc|orv|толокъно}}
*** {{desc|be|талакно́}}
*** {{desc|ru|толокно́}}
*** {{desc|uk|толокно́}}
** {{desc|bor=1|fi|talkkuna}}
* South Slavic:
** Slovene:
*** {{desc|bor=1|de|Dalken}}
** {{desc|bor=1|gmh|Talken}}
* West Slavic:
** {{desc|pl|tłukno}}
<pre>
{{hrow|2}}
* 111 111 111
* 222
* 333 333
* 4
* 5
* 6
* 7
</pre>
{{hrow|2}}
* 111 111 111
* 222
* 333 333
* 4
* 5
* 6
* 7
<includeonly>[[ကဏ္ဍ:ထာမ်ပလိက်မုက်လိက်တိုၚ်ကရေက်ဂမၠိုၚ်|hrow]]</includeonly>
6zzj23seiqn33b9v2an1czsipa1j7cv
ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်
14
297544
399840
2026-07-21T10:11:13Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]"
399840
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
ei9t0aingw95gozym8y64l6s32uipwj
ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
297545
399842
2026-07-21T10:15:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]"
399842
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
3porj5glr5vzkiuwrdbtvghj9vfxb1z
злобен
0
297546
399843
2026-07-21T10:21:54Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ===ဗွဟ်ရမ္သာၚ်=== * {{mk-IPA}} ====နာမဝိသေသန==== {{mk-adj}} # မယုတ်မာ၊ မပရေံ။ ====လဟုတ်စှ်ေ==== {{mk-decl-adj|злобн|c=1|fe=1}} ==ရုဿျှာ== ===ဗွဟ်ရမ္သာၚ်=== * {{ru-IPA|зло́бен}} ====နာမဝိသေသန==== {{head|ru|adjective form|..."
399843
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
===ဗွဟ်ရမ္သာၚ်===
* {{mk-IPA}}
====နာမဝိသေသန====
{{mk-adj}}
# မယုတ်မာ၊ မပရေံ။
====လဟုတ်စှ်ေ====
{{mk-decl-adj|злобн|c=1|fe=1}}
==ရုဿျှာ==
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́бен}}
====နာမဝိသေသန====
{{head|ru|adjective form|head=зло́бен}}
# {{inflection of|ru|зло́бный||short|m|s}}
j35qiky7mzidpcwp7genokxx1wdc9ce
ထာမ်ပလိက်:mk-decl-adj-table-full
10
297547
399844
2026-07-21T10:38:36Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{inflection-table-top|title={{#if:{{{title|}}}|{{{title}}}|{{#if:{{NAMESPACE}}||မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|mk||{{pagename}}|tr=-}}}}}}|palette=amber|tall=yes}} ! class="outer" | မချိုတ်ပၠိုတ် ! ပုလ္လိၚ် ! ဣတ္တိလိၚ် ! နပုလ္လိၚ် ! ကိုန်ဗဟုဝစ် |- ! ဟွံချိုတ်ပၠိ..."
399844
wikitext
text/x-wiki
{{inflection-table-top|title={{#if:{{{title|}}}|{{{title}}}|{{#if:{{NAMESPACE}}||မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|mk||{{pagename}}|tr=-}}}}}}|palette=amber|tall=yes}}
! class="outer" | မချိုတ်ပၠိုတ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
! ကိုန်ဗဟုဝစ်
|-
! ဟွံချိုတ်ပၠိုတ်
| {{#if:{{{ind_m|}}}|{{l-self|mk|{{{ind_m}}}}}|—}}
| {{#if:{{{ind_f|}}}|{{l-self|mk|{{{ind_f}}}|accel-form=indef{{!}}f{{!}}sg}}|—}}
| {{#if:{{{ind_n|}}}|{{l-self|mk|{{{ind_n}}}|accel-form=indef{{!}}n{{!}}sg}}|—}}
| {{#if:{{{ind_pl|}}}|{{l-self|mk|{{{ind_pl}}}|accel-form=indef{{!}}pl}}|—}}
|-
! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ်
| {{#if:{{{def_unsp_m|}}}|{{l-self|mk|{{{def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg}}|—}}
| {{#if:{{{def_unsp_f|}}}|{{l-self|mk|{{{def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg}}|—}}
| {{#if:{{{def_unsp_n|}}}|{{l-self|mk|{{{def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg}}|—}}
| {{#if:{{{def_unsp_pl|}}}|{{l-self|mk|{{{def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl}}|—}}
|-
! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ်
| {{#if:{{{def_prox_m|}}}|{{l-self|mk|{{{def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg}}|—}}
| {{#if:{{{def_prox_f|}}}|{{l-self|mk|{{{def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg}}|—}}
| {{#if:{{{def_prox_n|}}}|{{l-self|mk|{{{def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg}}|—}}
| {{#if:{{{def_prox_pl|}}}|{{l-self|mk|{{{def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl}}|—}}
|-
! ဇမ္ၚောဲမချိုတ်ပၠိုတ်
| {{#if:{{{def_dist_m|}}}|{{l-self|mk|{{{def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg}}|—}}
| {{#if:{{{def_dist_f|}}}|{{l-self|mk|{{{def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg}}|—}}
| {{#if:{{{def_dist_n|}}}|{{l-self|mk|{{{def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg}}|—}}
| {{#if:{{{def_dist_pl|}}}|{{l-self|mk|{{{def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl}}|—}}
|-
| class="separator" colspan="999" |
|-
! class="outer" | ပတဝ်ပတုပ်ရံၚ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
! ကိုန်ဗဟုဝစ်
|-
! ဟွံချိုတ်ပၠိုတ်
| {{#if:{{{c_ind_m|}}}|{{l-self|mk|{{{c_ind_m}}}|accel-form=indef{{!}}m{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_ind_f|}}}|{{l-self|mk|{{{c_ind_f}}}|accel-form=indef{{!}}f{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_ind_n|}}}|{{l-self|mk|{{{c_ind_n}}}|accel-form=indef{{!}}n{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_ind_pl|}}}|{{l-self|mk|{{{c_ind_pl}}}|accel-form=indef{{!}}pl{{!}}comd}}|—}}
|-
! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ်
| {{#if:{{{c_def_unsp_m|}}}|{{l-self|mk|{{{c_def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_unsp_f|}}}|{{l-self|mk|{{{c_def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_unsp_n|}}}|{{l-self|mk|{{{c_def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_unsp_pl|}}}|{{l-self|mk|{{{c_def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl{{!}}comd}}|—}}
|-
! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ်
| {{#if:{{{c_def_prox_m|}}}|{{l-self|mk|{{{c_def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_prox_f|}}}|{{l-self|mk|{{{c_def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_prox_n|}}}|{{l-self|mk|{{{c_def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_prox_pl|}}}|{{l-self|mk|{{{c_def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl{{!}}comd}}|—}}
|-
! ဇမ္ၚောဲမချိုတ်ပၠိုတ်
| {{#if:{{{c_def_dist_m|}}}|{{l-self|mk|{{{c_def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_dist_f|}}}|{{l-self|mk|{{{c_def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_dist_n|}}}|{{l-self|mk|{{{c_def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg{{!}}comd}}|—}}
| {{#if:{{{c_def_dist_pl|}}}|{{l-self|mk|{{{c_def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl{{!}}comd}}|—}}
|-
| class="separator" colspan="999" |
|-
! class="outer" | တၞုၚ်တၞောတ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
! plural
|-
! ဟွံချိုတ်ပၠိုတ်
| {{#if:{{{s_ind_m|}}}|{{l-self|mk|{{{s_ind_m}}}|accel-form=indef{{!}}m{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_ind_f|}}}|{{l-self|mk|{{{s_ind_f}}}|accel-form=indef{{!}}f{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_ind_n|}}}|{{l-self|mk|{{{s_ind_n}}}|accel-form=indef{{!}}n{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_ind_pl|}}}|{{l-self|mk|{{{s_ind_pl}}}|accel-form=indef{{!}}pl{{!}}supd}}|—}}
|-
! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ်
| {{#if:{{{s_def_unsp_m|}}}|{{l-self|mk|{{{s_def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_unsp_f|}}}|{{l-self|mk|{{{s_def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_unsp_n|}}}|{{l-self|mk|{{{s_def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_unsp_pl|}}}|{{l-self|mk|{{{s_def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl{{!}}supd}}|—}}
|-
! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ်
| {{#if:{{{s_def_prox_m|}}}|{{l-self|mk|{{{s_def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_prox_f|}}}|{{l-self|mk|{{{s_def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_prox_n|}}}|{{l-self|mk|{{{s_def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_prox_pl|}}}|{{l-self|mk|{{{s_def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl{{!}}supd}}|—}}
|-
! ဇမ္ၚောဲမချိုတ်ပၠိုတ်
| {{#if:{{{s_def_dist_m|}}}|{{l-self|mk|{{{s_def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_dist_f|}}}|{{l-self|mk|{{{s_def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_dist_n|}}}|{{l-self|mk|{{{s_def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg{{!}}supd}}|—}}
| {{#if:{{{s_def_dist_pl|}}}|{{l-self|mk|{{{s_def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl{{!}}supd}}|—}}
{{inflection-table-bottom}}<!--
--><noinclude>{{documentation}}</noinclude>
myyvnc6whdfotvq0hx9hfff4gc0aol8
ထာမ်ပလိက်:mk-decl-adj-table-full/documentation
10
297548
399845
2026-07-21T10:50:40Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{isAccelerated}} For Macedonian adjectives. In the first parameter, one should indicate the contracted stem used before vowel-initial endings if there is a fleeting vowel, e.g. "добр" for {{l|mk|добар|tr=-}}. If there is no fleeting vowel, nothing needs to be indicated, as for {{l|mk|зрел|tr=-}}. However, if the masculine singular indefinite ends in -и, as in {{l|mk|градс..."
399845
wikitext
text/x-wiki
{{documentation subpage}}
{{isAccelerated}}
For Macedonian adjectives. In the first parameter, one should indicate the contracted stem used before vowel-initial endings if there is a fleeting vowel, e.g. "добр" for {{l|mk|добар|tr=-}}. If there is no fleeting vowel, nothing needs to be indicated, as for {{l|mk|зрел|tr=-}}. However, if the masculine singular indefinite ends in -и, as in {{l|mk|градски|tr=-}}, the stem without the -и needs to be indicated in the first parameter so that the -и doesn't transfer to other forms. If the adjective has comparative and superlative forms, c=1 should be written in a separate parameter; in the absence of this specification, only positive forms will be generated.
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်မက်သဳဒဝ်နဳယျာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်| ]]
</includeonly>
p4qsmyepquxux3q25oulalbnn8iq3nk
позлобен
0
297549
399846
2026-07-21T11:44:54Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ====နာမဝိသေသန==== {{head|mk|နာမဝိသေသန}} # {{comparative of|mk|злобен}}"
399846
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
====နာမဝိသေသန====
{{head|mk|နာမဝိသေသန}}
# {{comparative of|mk|злобен}}
n8oqiwakl8n6rv0r9p64kn5jpp5obp2
најзлобен
0
297550
399847
2026-07-21T11:52:18Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ====နာမဝိသေသန==== {{head|mk|နာမဝိသေသန}} # {{superlative of|mk|злобен}}"
399847
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
====နာမဝိသေသန====
{{head|mk|နာမဝိသေသန}}
# {{superlative of|mk|злобен}}
47ueh8nazzn0dujf9qj66f1mbk9tryi
злобный
0
297551
399848
2026-07-21T12:40:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== {{was wotd|၂၀၂၆|ဂျူလာင်|၂၂}} ===ဗွဟ်ရမ္သာၚ်=== * {{ru-IPA|зло́бный}} * {{audio|ru|Ru-злобный.ogg}} ====နာမဝိသေသန==== {{ru-adj|зло́бный|+|peri|adv=зло́бно|absn=зло́бность|dim=зло́бненький}} # မဂိဓဇောတ်၊ မၞုံကဵုသဒှ်ဒက်လဝ်ဝ..."
399848
wikitext
text/x-wiki
==ရုဿျှာ==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၂}}
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́бный}}
* {{audio|ru|Ru-злобный.ogg}}
====နာမဝိသေသန====
{{ru-adj|зло́бный|+|peri|adv=зло́бно|absn=зло́бность|dim=зло́бненький}}
# မဂိဓဇောတ်၊ မၞုံကဵုသဒှ်ဒက်လဝ်ဝဲ၊ မၞုံကဵုစိုတ်ညးတၞဟ်ခိုဟ်စဟွံဒးစိုတ်၊ မၞုံကဵုစိုတ်ဂၠာဲသၞညးတၞဟ်၊ မလေပ်တ္ၚံက်ဍုတ်ဍေဲ၊ မၞုံကဵုစိုတ်ယုတ်လ္တူညးတၞဟ်။
====လဟုတ်စှ်ေ====
{{ru-decl-adj|зло́бный|a*}}
0yigsdgkm5ad7tho5fmwdsjr6kwc4ys
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၂
4
297552
399849
2026-07-21T12:44:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|злобный|နာမဝိသေသန| မဂိဓဇောတ်၊ မၞုံကဵုသဒှ်ဒက်လဝ်ဝဲ၊ မၞုံကဵုစိုတ်ညးတၞဟ်ခိုဟ်စဟွံဒးစိုတ်၊ မၞုံကဵုစိုတ်ဂၠာဲသၞညးတၞဟ်၊ မလေပ်တ္ၚံက်ဍုတ်ဍေဲ၊ မၞုံကဵုစိုတ်..."
399849
wikitext
text/x-wiki
{{WOTD|злобный|နာမဝိသေသန| မဂိဓဇောတ်၊ မၞုံကဵုသဒှ်ဒက်လဝ်ဝဲ၊ မၞုံကဵုစိုတ်ညးတၞဟ်ခိုဟ်စဟွံဒးစိုတ်၊ မၞုံကဵုစိုတ်ဂၠာဲသၞညးတၞဟ်၊ မလေပ်တ္ၚံက်ဍုတ်ဍေဲ၊ မၞုံကဵုစိုတ်ယုတ်လ္တူညးတၞဟ်။|audio=Ru-злобный.ogg|ဂျူလာင်|၂၂}}
cj5y0y9qep8v4x06p2q9fmamgy8dnwo
ထာမ်ပလိက်:ru-adj/documentation
10
297553
399853
2026-07-21T14:31:23Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|Module:ru-headword}} This template is used for the headword line of Russian adjectives. ==Parameters== ; {{para|1}} : The headword(s) with accents. This is also used to link to individual words in a page title. Leave it blank to use the page name as the default (only appropriate if the headword is monosyllabic or has a {{lang|ru|ё}} in it). Multiple comma-separated items are allo..."
399853
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:ru-headword}}
This template is used for the headword line of Russian adjectives.
==Parameters==
; {{para|1}}
: The headword(s) with accents. This is also used to link to individual words in a page title. Leave it blank to use the page name as the default (only appropriate if the headword is monosyllabic or has a {{lang|ru|ё}} in it). Multiple comma-separated items are allowed, along with per-item inline modifiers (see below).
; {{para|2}}
: The comparative form with accents. Leave it blank if you don't know the comparative. Multiple comma-separated items are allowed, along with per-item inline modifiers (see below).
:* Use <code>+b</code>, <code>+c'</code> etc. to form the comparative the "normal" way; the code after the + sign is the short adjective class. The short adjective class should leave out any notations like <code>*</code>, <code>(1)</code>, <code>(2)</code>, etc.
:* Use <code>+</code> to form the comparative the "normal" way if the short adjective class is <code>a</code> (or a variant such as <code>a*</code> or <code>a(1)</code>). This corresponds to the vast majority of adjectives (but not most of the most common ones).
:* Use <code>peri</code> if the comparative is formed with {{m|ru|бо́лее}}.
:* Use <code>-</code> if the adjective is not comparable.
; {{para|3}}
: The superlative form with accents. Normally only provided if a single-word superlative exists (e.g. {{m|ru|нове́йший}} of {{m|ru|но́вый}}); but the code <code>peri</code> can used if the superlative is formed with {{m|ru|са́мый}}. Multiple comma-separated items are allowed, along with per-item inline modifiers (see below).
; {{para|adv}}
: Adverb(s) associated with this adjective. Multiple comma-separated items are allowed, along with per-item inline modifiers (see below).
; {{para|absn}}
: Abstract noun(s) associated with this adjective. Multiple comma-separated items are allowed, along with per-item inline modifiers (see below). Use {{cd|+}} to generate a default abstract noun ending in -ость.
; {{para|dim}}
: Diminutives(s) associated with this adjective. Multiple comma-separated items are allowed, along with per-item inline modifiers (see below).
; {{para|indecl|1}}
: Indicate that the adjective is indeclinable, e.g. {{m|ru|беж||[[beige]]}} or {{m|ru|не́тто|tr=nétto, nɛ́tto||[[net]] {{i|of weight}}}}. This puts an indication of this in the headword and inserts the adjective into [[:Category:Russian indeclinable adjectives]].
; {{para|noinf|1}}
: Indicate that no informal variants of comparatives should be listed. If not supplied, informal comparative variants (ending in {{lang|ru|-ей}} instead of {{lang|ru|-ее}}) will automatically be listed along with normal comparatives, for comparatives ending in {{lang|ru|-ее}} or {{lang|ru|-е́е}}.
===Inline modifiers===
All params above that specify Cyrillic terms support ''inline modifiers'', e.g. {{para|dim|ти́хенький<l:rare>}} to attach a label ''rare'' to a diminutive. The following modifiers are recognized:
* <code>tr</code>: manual translit; separate multiple translits with a comma
* <code>q</code>: qualifier, e.g. {{cd|<q:in the plural>}} or {{cd|<q:when referring to a card game>}}; this appears *BEFORE* the term, parenthesized and italicized
* <code>qq</code>: qualifier, e.g. {{cd|<qq:in the plural>}} or {{cd|<qq:when referring to a card game>}}; this appears *AFTER* the term, parenthesized and italicized
* <code>l</code>: comma-separated list of labels, e.g. {{cd|<l:rare>}} or {{cd|<l:dated,or,literary>}}; this appears *BEFORE* the term, parenthesized and italicized
* <code>ll</code>: comma-separated list of labels, e.g. {{cd|<ll:rare>}} or {{cd|<ll:dated,or,literary>}}; this appears *AFTER* the term, parenthesized and italicized
* <code>ref</code>: one or more references, in the format documented in [[Module:references]] and {{tl|IPA}}
* <code>id</code>: sense ID; see {{temp|senseid}}; cannot be specified with headwords as it doesn't make sense to do so
* <code>unknown_stress</code>: specify {{cd|<unknown_stress:1>}} and leave out the acute accent if the word has multiple syllables and you don't where the stress goes; if omitted and the stress is left out, an error will occur
* <code>nostress</code>: specify {{cd|<nostress:1>}} if there is actually no stress on a multisyllabic word
{{hwcat}}
==Examples==
{{demo|<nowiki>{{ru-adj|то́нкий|то́ньше|тонча́йший|pagename=тонкий}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|ста́рший|ста́рше|peri|pagename=старший}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|теку́чий|peri|peri|pagename=текучий}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|высо́кий|вы́ше|высоча́йший,вы́сший|pagename=высокий}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|пла́вный|+a'|pagename=плавный}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|безра́достный|+|absn=+|pagename=безрадостный}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|ру́сский|-|pagename=русский}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|ти́хий|ти́ше|тиша́йший|adv=ти́хо|absn=тишина́|pagename=тихий}}</nowiki>}}
{{demo|<nowiki>{{ru-adj|не́тто<tr:nétto, nɛ́tto>|indecl=1|pagename=нетто}}</nowiki>}}
{{hwcat}}
3h0oxddtu8w7kftns50nfnekhrhyc6v
မဝ်ဂျူ:ru-headword/documentation
828
297554
399855
2026-07-22T23:39:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module is used by many of the [[:ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ရုဿျှာဂမၠိုၚ်|Russian headword-line templates]]: {{temp|ru-noun}}, {{temp|ru-proper noun}}, {{temp|ru-proper noun+}}, {{temp|ru-adj}}, {{temp|ru-verb}}, {{temp|ru-verb-cform}}, {{temp|ru-adv}}. <includeonly> {{module cat|ru}} </includeonly>"
399855
wikitext
text/x-wiki
This module is used by many of the [[:ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ရုဿျှာဂမၠိုၚ်|Russian headword-line templates]]: {{temp|ru-noun}}, {{temp|ru-proper noun}}, {{temp|ru-proper noun+}}, {{temp|ru-adj}}, {{temp|ru-verb}}, {{temp|ru-verb-cform}}, {{temp|ru-adv}}.
<includeonly>
{{module cat|ru}}
</includeonly>
okbo0os4boj66m3hyetcym56u198d8f
399856
399855
2026-07-22T23:40:03Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:ru-headword/doc]] ဇရေင် [[မဝ်ဂျူ:ru-headword/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399855
wikitext
text/x-wiki
This module is used by many of the [[:ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်ရုဿျှာဂမၠိုၚ်|Russian headword-line templates]]: {{temp|ru-noun}}, {{temp|ru-proper noun}}, {{temp|ru-proper noun+}}, {{temp|ru-adj}}, {{temp|ru-verb}}, {{temp|ru-verb-cform}}, {{temp|ru-adv}}.
<includeonly>
{{module cat|ru}}
</includeonly>
okbo0os4boj66m3hyetcym56u198d8f
မဝ်ဂျူ:ru-common/documentation
828
297555
399858
2026-07-22T23:55:51Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==Exported functions== {{module documentation}} {{module cat}}"
399858
wikitext
text/x-wiki
==Exported functions==
{{module documentation}}
{{module cat}}
erx8nqy3l8697of8ok2g0vpaseexkg0
399859
399858
2026-07-22T23:56:26Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:ru-common/doc]] ဇရေင် [[မဝ်ဂျူ:ru-common/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399858
wikitext
text/x-wiki
==Exported functions==
{{module documentation}}
{{module cat}}
erx8nqy3l8697of8ok2g0vpaseexkg0
ထာမ်ပလိက်:ru-decl-adj
10
297556
399860
2026-07-23T00:08:49Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{#invoke:ru-adjective|show}}</includeonly><noinclude>{{documentation}}</noinclude>"
399860
wikitext
text/x-wiki
<includeonly>{{#invoke:ru-adjective|show}}</includeonly><noinclude>{{documentation}}</noinclude>
9wrldq3x2s4taa85fhbe16f4tbfw8g4
ထာမ်ပလိက်:ru-decl-adj/documentation
10
297557
399861
2026-07-23T00:11:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} This is the template for creating a Russian adjective declension table, using [[Module:ru-adjective]]. ==Parameters== ; {{para|1}} : Lemma, with appropriately placed accent(s); or stem, if the declension class is explicitly given in {{para|2}}. ; {{para|2}} : Declension class (usually omitted to autodetect based on the lemma), along with any short accent type and optional irregular short st..."
399861
wikitext
text/x-wiki
{{documentation subpage}}
This is the template for creating a Russian adjective declension table, using [[Module:ru-adjective]].
==Parameters==
; {{para|1}}
: Lemma, with appropriately placed accent(s); or stem, if the declension class is explicitly given in {{para|2}}.
; {{para|2}}
: Declension class (usually omitted to autodetect based on the lemma), along with any short accent type and optional irregular short stem; see below.
; {{para|suffix}}
: Optional suffix to add unchanged to each form.
; {{para|title}}
: Override the table title.
; {{para|nom_m}}, {{para|nom_n}}, {{para|nom_f}}, {{para|nom_p}}, {{para|gen_m}}, {{para|gen_f}}, {{para|gen_p}}, {{para|dat_m}}, {{para|dat_f}}, {{para|dat_p}}, {{para|acc_f}}, {{para|acc_n}}, {{para|ins_m}}, {{para|ins_f}}, {{para|ins_p}}, {{para|pre_m}}, {{para|pre_f}}, {{para|pre_p}}, {{para|short_m}}, {{para|short_n}}, {{para|short_f}}, {{para|short_p}}; also {{para|nom_mp}} for old-style declension tables ({{para|old|1}}) and два/оба/compounds of два ({{para|special|*}}); also {{para|nom_fp}} for два/оба/compounds of два ({{para|special|*}}); also {{para|gen_mp}}, {{para|gen_fp}}, {{para|dat_mp}}, {{para|dat_fp}}, {{para|ins_mp}}, {{para|ins_fp}}, {{para|pre_mp}}, {{para|pre_fp}} for оба ({{para|special|oba}})
: Override one or more declensional forms (nominative, genitive, dative, accusative, instrumental, prepositional, partitive, locative, vocative, short-form; masculine, feminine, neuter, plural, masculine plural, feminine plural). Alternatives may be separated by commas. Overridden forms, including comma-separated alternatives, will automatically be linked; but if you include a form along with other text (e.g. parens or a *), you should manually insert a link (it is OK to just use brackets around the link, even with stress marks in the form).
; {{para|shorttail}}
: Footnote symbol (e.g. *, 1, 2, etc.) to add to the last short form if there's more than one; automatically superscripted. Used in conjunction with {{para|notes}} to add a footnote to the short forms. This works like {{temp|ru-noun-table}}; see the documentation for that template for more information on footnotes and footnote symbols.
; {{para|shorttailall}}
: Like {{para|shorttail}} but appended to all short forms, including when there's only one.
; {{para|CASE_NUMGEN_tail}}
: Append a footnote symbol to the last form for a particular case/number/gender combination. Note that this differs from {{para|shorttail}} in that it will be appended even if there's only one form. The possible values of CASE_NUMGEN are the same as for overrides.
; {{para|CASE_NUMGEN_tailall}}
: Same but appends to all forms, as with {{para|shorttailall}}.
; {{para|notes}}
: Note(s) to insert into the table. An initial footnote symbol (e.g. *, 1, 2, etc.) is automatically superscripted.
: {{para|special}}
: Use special tables for adjective-like numerals (два, оба, compounds of два). See below.
===Declension spec===
The form of the declension spec (argument 2) is DECLSPEC or DECLSPEC,DECLSPEC,... where DECLSPEC is one of the following:
# DECLCLASS:SHORTACCENT:SHORTSTEM
# DECLCLASS:SHORTACCENT
# DECLCLASS
# SHORTACCENT:SHORTSTEM
# SHORTSTEM
# (blank)
DECLCLASS should normally be omitted, and the declension autodetected from the ending; or it should be <code>ь</code>, to indicate that an adjective in -ий is of the possessive variety with an extra -ь- in most of the endings. Alternatively, it can be an explicit declension class, in which case the lemma field needs to be replaced with the bare stem; the following are the possibilities:
* <code>ый</code>, <code>ий</code>, <code>ой</code>, <code>ьий</code> (for long adjectives)
* <code>ій</code>, <code>ьій</code> (for long adjectives with pre-reform spelling, in place of <code>ий</code> and <code>ьий</code>)
* <code>short</code>, <code>stressed-short</code>, <code>mixed</code>, <code>proper</code>, <code>stressed-proper</code> (for short or mixed adjectives, i.e. those ending in -ов, -ин, or similar)
* <code>ъ-short</code>, <code>ъ-stressed-short</code>, <code>ъ-mixed</code>, <code>ъ-proper</code>, <code>ъ-stressed-proper</code> (aliases of the above; can be used with pre-reform adjectives to emphasize the ending in -ъ, but not required)
SHORTACCENT is one of <code>a</code> <code>a'</code> <code>b</code> <code>b'</code> <code>c</code> <code>c'</code> <code>c<nowiki>''</nowiki></code> to auto-generate the short forms with the specified accent pattern (following Zaliznyak, see below); if omitted, no short forms will be auto-generated. SHORTACCENT can also contain the following special-case markers:
* <code>*</code> for reducible "reducible" adjectives, where the short masculine singular has an epenthetic vowel in the final syllable
* <code>(1)</code> for use with adjectives in -нный/-нний, causing the short masculine singular to end in -н instead of -нн
* <code>(2)</code> for use with adjectives in -нный/-нний, causing all short forms to end in -н instead of -нн
SHORTSTEM, if present, is used as the short stem to base the short forms off of, instead of the normal adjective long stem (possibly with a final-syllable accent added in the case of declension class <code>ой</code>).
===Short accent types===
{|class="wikitable" style="text-align: center;"
! Type !! Masculine accent !! Feminine accent !! Neuter accent !! Plural accent
|-
| <code>a</code> || colspan=4|stem
|-
| <code>a'</code> || stem || ending or stem || colspan=2|stem
|-
| <code>b</code> || colspan=4|ending
|-
| <code>b'</code> || colspan=3|ending || ending or stem
|-
| <code>c</code> || stem || ending || colspan=2|stem
|-
| <code>c'</code> || stem || ending || stem || ending or stem
|-
| <code>c''</code> || stem || ending || colspan=2|ending or stem
|}
===Declension classes===
The following table lists the explicit declensional classes. "Old class" is the class for use with {{para|old|1}}, which creates old-style (pre-1918) adjective templates. Note that in normal usage you should not include explicit declension classes, but should include the full lemma in argument 1 and allow the declension class to be autodetected.
{|class="wikitable" style="text-align: center;"
! Class !! Old class !! Nominative ending !! Old nominative ending !! Comments
|-
| colspan=2|<code>ый</code> || colspan=2|ый ||
|-
| <code>ий</code> || <code>ій</code> || ий || ій ||
|-
| colspan=2|<code>ой</code> || colspan=2|о́й ||
|-
| <code>ьий</code> || <code>ьій</code> || ий || ій || possessive -ий, e.g. {{m|ru|ры́бий}} (old-style {{m|ru|ры́бій}})
|-
| <code>short</code> || <code>short</code>, <code>ъ-short</code> || (none) || ъ || possessive -ов, -ёв, -ев, e.g. {{m|ru|отцо́в}} (old-style {{m|ru|отцо́въ}})
|-
| <code>stressed-short</code> || <code>stressed-short</code>, <code>ъ-stressed-short</code> || (none) || ъ || possessive -ин with stressed endings, e.g. {{m|ru|фоми́н}}
|-
| <code>mixed</code> || <code>mixed</code>, <code>ъ-mixed</code> || (none) || ъ || possessive -ин, -ын, e.g. {{m|ru|ма́мин}}
|-
| <code>proper</code> || <code>proper</code>, <code>ъ-proper</code> || (none) || ъ || possessive proper nouns in -ов, -ёв, -ев, -ин, -ын, with feminine but no neuter, e.g. {{m|ru|Попо́в}}, {{m|ru|Ре́пин}}
|-
| <code>stressed-proper</code> || <code>stressed-proper</code>, <code>ъ-stressed-proper</code> || (none) || ъ || possessive proper nouns in -и́н, -ы́н with stressed endings, e.g. {{m|ru|Бороди́н}} (genitive {{m|ru|Бородина́}})
|-
| <code>manual</code> || <code>manual</code> || (any) || (any) || used with explicit overrides for all forms; unspecified forms default to "-"
|-
|}
===Auto-accenting and required accents===
Multisyllabic words in arguments (lemma, short stem, overrides) normally need a stress mark in them (as in а́, ы́, ё or ѣ̈) to indicate the position of the stress; an error will occur otherwise. Accents are not required on monosyllabic words, which will automatically be stressed on their only vowel. You can override both accent errors and auto-accenting by prefixing the lemma with <code>*</code>. (Don't use this prefix on other arguments. If present on the lemma, it applies to all arguments.) This is useful when a word has no stress (e.g. unstressed suffixes) or when the stress is unknown.
===Manual transliteration===
All parameters that accept Russian text can be followed by <code>//</code> and a manual transliteration. Transformations of the Russian text (e.g. reducing, dereducing, moving the stress) will appropriately be applied to the manual transliteration as well. Certain rules need to be respected concerning the manual transliteration, and will trigger errors if not. For example, the manual transliteration needs to have the same number of syllables as the Russian, and the manual transliteration of the lemma needs to have the same declensional ending (e.g. -ый, -ой, -ъ), or rather its transliteration.
===Special numeral templates===
Special support is present for {{m|ru|два}}, {{m|ru|оба}} and compounds of два, e.g. {{m|ru|два́дцать два́}}. These numerals are supported, respectively, using {{para|special|dva}}, {{para|special|oba}} and {{para|special|cdva}}. These should be used in conjunction with manually-specified declensions and explicit overrides for all forms. Three different special cases are required:
* два has distinct masculine/neuter from feminine in the nominative and inanimate accusative only, along with an animacy distinction.
* оба has distinct masculine/neuter from feminine in all cases, along with an animacy distinction.
* Compounds of два are like два but have no animacy distinction.
See the example below.
==Examples==
===Example 1===
The adjective {{m|ru|ара́бский||Arabic, Arab}} has no short forms.
<code><nowiki>{{ru-decl-adj|ара́бский}}</nowiki></code>
produces
{{ru-decl-adj|ара́бский}}
===Example 2===
The adjective {{m|ru|анони́мный||anonymous}} has stem-stressed short forms (type <code>a</code>), and the masculine singular {{m|ru|анони́мен}} has an epenthetic vowel, indicated by the reducible declension symbol <code>*</code>.
<code><nowiki>{{ru-decl-adj|анони́мный|a*}}</nowiki></code>
produces
{{ru-decl-adj|анони́мный|a*}}
===Example 3===
The adjective {{m|ru|о́стрый||short, critical, hot (of food)}} has stem-stressed short masculine and neuter singular and either stem or ending stress in the feminine singular and the plural (type <code>c''</code>). In addition, it has an epenthetic vowel in the masculine singular, but the form is irregular {{m|ru|остёр}} instead of expected {{m|ru|о́стер}}; hence an override is needed.
<code><nowiki>{{ru-decl-adj|о́стрый|c''*|short_m=остёр}}</nowiki></code>
produces
{{ru-decl-adj|о́стрый|c''*|short_m=остёр}}
===Example 4===
The adjective {{m|ru|нра́вственный||moral}} has stem-stressed short forms. The masculine singular short form can be either {{m|ru|нра́вственен}} (reducible declension symbol <code>*</code>) or {{m|ru|нра́вствен}} (special-case symbol <code>(1)</code>).
<code><nowiki>{{ru-decl-adj|нра́вственный|a*,a(1)}}</nowiki></code>
produces
{{ru-decl-adj|нра́вственный|a*,a(1)}}
===Example 5===
The adjective {{m|ru|и́скренний||sincere}} has reducible short masculine singular {{m|ru|и́скренен}} (type <code>a</code>, reducible declension symbol <code>*</code>). The remaining short forms are irregular or have irregular alternatives, requiring overrides.
<code><nowiki>{{ru-decl-adj|и́скренний|a*|short_n=и́скренне,и́скренно|short_f=и́скренна|short_p=и́скренни,и́скренны}}</nowiki></code>
produces
{{ru-decl-adj|и́скренний|a*|short_n=и́скренне,и́скренно|short_f=и́скренна|short_p=и́скренни,и́скренны}}
===Example 6===
The adjective {{m|ru|большо́й||big}} has short forms with a completely different stem, e.g. masculine singular {{m|ru|вели́к}}, feminine singular {{m|ru|велика́}} (type <code>b</code>).
<code><nowiki>{{ru-decl-adj|большо́й|b:вели́к}}</nowiki></code>
produces
{{ru-decl-adj|большо́й|b:вели́к}}
===Example 7===
The adjective {{m|ru|стре́ссовый|tr=strɛ́ssovyj||related to stress}} requires manual transliteration.
<code><nowiki>{{ru-decl-adj|стре́ссовый//strɛ́ssovyj}}</nowiki></code>
produces
{{ru-decl-adj|стре́ссовый//strɛ́ssovyj}}
===Example 8===
The numeral {{m|ru|два́дцать два́||twenty-two}} requires use of a special template.
<code><nowiki>{{ru-decl-adj|-|manual|nom_mp=два́дцать два|nom_fp=два́дцать две|gen_p=двадцати́ двух|dat_p=двадцати́ двум|ins_p=двадцатью́ двумя́|pre_p=двадцати́ двух|special=cdva}}</nowiki></code>
produces
{{ru-decl-adj|-|manual|nom_mp=два́дцать два|nom_fp=два́дцать две|gen_p=двадцати́ двух|dat_p=двадцати́ двум|ins_p=двадцатью́ двумя́|pre_p=двадцати́ двух|special=cdva}}
===Example 9===
The adjective {{m|ru|недорого́й|t=cheap, inexpensive}} has stem-stressed short forms in the masculine, neuter, and plural, (type <code>c</code>), but the end-stressing suffix [[-ой|-о́й]] in its long forms, requiring the second and third values of parameter {{para|2}} (<code>SHORTACCENT:SHORTSTEM</code>) to avoid end stress.
<code><nowiki>{{ru-decl-adj|недорого́й|c:недо́рог}}</nowiki></code>
produces
{{ru-decl-adj|недорого́й|c:недо́рог}}
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်]]
</includeonly>
7usfl49ir9xovzcran00no7155of6xh
မဝ်ဂျူ:ru-adjective/documentation
828
297558
399863
2026-07-23T00:47:43Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module implements {{temp|ru-decl-adj}} and {{temp|ru-decl-adj-irreg}}, as well as {{temp|ru-generate-adj-forms}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]]. <includeonly> {{module cat|ru}} </includeonly>"
399863
wikitext
text/x-wiki
This module implements {{temp|ru-decl-adj}} and {{temp|ru-decl-adj-irreg}}, as well as {{temp|ru-generate-adj-forms}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]].
<includeonly>
{{module cat|ru}}
</includeonly>
4gyhz1z3rmdkrs4vdeud05vnm9hxks2
399864
399863
2026-07-23T00:48:13Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:ru-adjective/doc]] ဇရေင် [[မဝ်ဂျူ:ru-adjective/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399863
wikitext
text/x-wiki
This module implements {{temp|ru-decl-adj}} and {{temp|ru-decl-adj-irreg}}, as well as {{temp|ru-generate-adj-forms}}. It is not meant to be invoked directly from user code. If you have questions about it, please contact [[User:Benwing2]].
<includeonly>
{{module cat|ru}}
</includeonly>
4gyhz1z3rmdkrs4vdeud05vnm9hxks2
ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်
14
297559
399866
2026-07-23T00:54:23Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]"
399866
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ရုဿျှာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ရ]]
6zrboiw7x7mjt2psrhrixttm0evsazf
злобнее
0
297560
399867
2026-07-23T00:57:25Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{comparative of|ru|злобный}}"
399867
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{comparative of|ru|злобный}}
23hxk2zcu8wx4iayc90ou1p3fg4hz0s
позлобнее
0
297561
399868
2026-07-23T00:57:55Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{comparative of|ru|злобный}}"
399868
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{comparative of|ru|злобный}}
23hxk2zcu8wx4iayc90ou1p3fg4hz0s
позлобней
0
297562
399869
2026-07-23T00:58:14Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{comparative of|ru|злобный}}"
399869
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{comparative of|ru|злобный}}
23hxk2zcu8wx4iayc90ou1p3fg4hz0s
злобней
0
297563
399870
2026-07-23T00:58:29Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{comparative of|ru|злобный}}"
399870
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{comparative of|ru|злобный}}
23hxk2zcu8wx4iayc90ou1p3fg4hz0s
самый
0
297564
399871
2026-07-23T00:59:00Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{superlative of|ru|злобный}}"
399871
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{superlative of|ru|злобный}}
hjwg57b14nglaatevzxp3h55v4q5upm
399872
399871
2026-07-23T01:02:16Z
咽頭べさ
33
399872
wikitext
text/x-wiki
==ရုဿျှာ==
===နိရုတ်===
{{inh+|ru|sla-pro|*samъ}}
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|са́мый}}
* {{audio|ru|Ru-самый.ogg}}
===သဗ္ဗနာမ်===
{{head|ru|pronoun|head=са́мый}}
# မဆေၚ်စပ်ကဵုဗွဲမလောန်။
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{superlative of|ru|злобный}}
====လဟုတ်စှ်ေ====
{{ru-decl-adj|са́мый}}
{{ru-decl-adj|old=1|са́мый}}
===မဒုၚ်လွဳစ===
* {{desc|izh|samoi|bor=1}}
* {{desc|sjd|самэ|bor=1}}
* {{desc|sah|саамай|bor=1}}
brm6p4cz4iocl1ri37biggtna6iqq8o
ဗီုပြၚ်သိုၚ်တၟိ:သလာဗေတ်-အခိုက်ကၞာ/samъ
118
297565
399874
2026-07-23T01:16:55Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{reconstructed}} ==သလာဗေတ်-အခိုက်ကၞာ== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{inh|sla-pro|ine-pro|*somHós}} ===သဗ္ဗနာမ်=== {{sla-pron}} # ဇကုဇကု၊ အနေကဇကု။ ====လဟုတ်စှ်ေ==== {{sla-decl-pron-hard|sa|m}} ===မဒုၚ်လွဳစ=== {{hrow}} * {{desc|zle|-}} ** {{desc|orv|самъ}} *** {{d..."
399874
wikitext
text/x-wiki
{{reconstructed}}
==သလာဗေတ်-အခိုက်ကၞာ==
===နိရုတ်===
ဝေါဟာကၠုၚ်နူ {{inh|sla-pro|ine-pro|*somHós}}
===သဗ္ဗနာမ်===
{{sla-pron}}
# ဇကုဇကု၊ အနေကဇကု။
====လဟုတ်စှ်ေ====
{{sla-decl-pron-hard|sa|m}}
===မဒုၚ်လွဳစ===
{{hrow}}
* {{desc|zle|-}}
** {{desc|orv|самъ}}
*** {{desc|zle-ort|самъ}}
**** {{desc|be|сам}}
**** {{desc|rue|сам}}
**** {{desc|uk|сам}}
*** {{desc|ru|сам}}
** {{desc|zle-ono|саме}}
* {{desc|zls|-}}
** {{desc|cu|-}}
**: {{desc|sclang=1|cu|самъ}}
**: {{desc|sclang=1|cu|ⱄⰰⰿⱏ}}
*** {{desc|bg|сам}}
*** {{desc|mk|сам}}
** {{desc|sh|-}}
**: {{desc|sclang=1|sh|са̑м}}
**: {{desc|sclang=1|sh|sȃm}}
** {{desc|sl|sam}}
* {{desc|zlw|-}}
** {{desc|zlw-ocs|sám}}
*** {{desc|cs|sám}}
** {{desctree|zlw-opl|sam}}
** {{desc|zlw-osk|sám}}
*** {{desc|rsk|сам}}
*** {{desc|sk|sám}}
** {{desc|zlw-pom|-}}
*** {{desc|csb|sóm}}
*** {{desc|zlw-slv|sóm}}
** {{desc|wen|-}}
*** {{desc|hsb|sam}}
*** {{desc|dsb|sam}}
====နာမဝိသေသန====
{{sla-adj}}
# မဒှ်တုပ်တုပ်၊ သၟဟ်။
# ညးမွဲဓဝ်၊ နူအနေဇကု၊ အနေဇကုမွဲဓဝ်။
# မဆေၚ်စပ်ကဵုဗွဲမလောန်။
====လဟုတ်စှ်ေ====
{{sla-decl-adj-hard|sa|m}}
===မဒုၚ်လွဳစ===
{{hrow}}
* {{desc|zle|-}}
** {{desc|orv|самъ}}
*** {{desc|zle-ort|са́мый}}
**** {{desc|be|са́мы}}
**** {{desc|rue|са́мый}}
**** {{desc|uk|са́мий}}
*** {{desc|ru|са́мый}}
* {{desc|zls|-}}
** {{desc|cu|-}}
**: {{desc|sclang=1|cu|самъ}}
**: {{desc|sclang=1|cu|ⱄⰰⰿⱏ}}
*** {{desc|bg|сам}}
*** {{desc|mk|сам}}
** {{desc|sh|-}}
**: {{desc|sclang=1|sh|са̑м}}
**: {{desc|sclang=1|sh|sȃm}}
** {{desc/sl-tonal|sȃm}}
* {{desc|zlw|-}}
** {{desc|cs|samý}}
** {{desctree|zlw-opl|sam}}
** {{desc|zlw-pom|-}}
*** {{desc|csb|sóm}}
*** {{desc|zlw-slv|sóm}}
iuplydddunvznqo77wl5wik5vly2uj2
ထာမ်ပလိက်:sla-decl-pron-hard
10
297566
399875
2026-07-23T01:19:19Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|error}}<!-- Validate template parameters -->{{sla-decl-pron-table<!-- -->|title={{{title|Declension of {{m-self|sla-pro|*{{pagename}}}} (hard pronominal)}}}<!-- Singular -->|*{{{1}}}{{{2}}}ъ<!-- -->|*{{{1}}}{{{2}}}ъ<!-- -->|*{{{1}}}{{{2}}}ogo<!-- -->|*{{{1}}}{{{2}}}omь<!-- -->|*{{{1}}}{{{2}}}omu<!-- -->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmь<!-- -->|*{{{1}}}{{{2}}}a<!-- -->|*{{{1}}}{{{2}}}ǫ<!--..."
399875
wikitext
text/x-wiki
{{#invoke:checkparams|error}}<!-- Validate template parameters
-->{{sla-decl-pron-table<!--
-->|title={{{title|Declension of {{m-self|sla-pro|*{{pagename}}}} (hard pronominal)}}}<!--
Singular
-->|*{{{1}}}{{{2}}}ъ<!--
-->|*{{{1}}}{{{2}}}ъ<!--
-->|*{{{1}}}{{{2}}}ogo<!--
-->|*{{{1}}}{{{2}}}omь<!--
-->|*{{{1}}}{{{2}}}omu<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmь<!--
-->|*{{{1}}}{{{2}}}a<!--
-->|*{{{1}}}{{{2}}}ǫ<!--
-->|*{{{1}}}{{{2}}}oję̇<!--
-->|*{{{1}}}{{{2}}}oji<!--
-->|*{{{1}}}{{{2}}}oji<!--
-->|*{{{1}}}{{{2}}}ojǫ<!--
-->|*{{{1}}}{{{2}}}o<!--
-->|*{{{1}}}{{{2}}}o<!--
-->|*{{{1}}}{{{2}}}ogo<!--
-->|*{{{1}}}{{{2}}}omь<!--
-->|*{{{1}}}{{{2}}}omu<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmь<!--
Dual
-->|*{{{1}}}{{{2}}}a<!--
-->|*{{{1}}}{{{2}}}a<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{{2}}}oju<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěma<!--
Plural
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|*{{{1}}}{{{2}}}y<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmi<!--
-->|*{{{1}}}{{{2}}}y<!--
-->|*{{{1}}}{{{2}}}y<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmi<!--
-->|*{{{1}}}{{{2}}}a<!--
-->|*{{{1}}}{{{2}}}a<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmъ<!--
-->|*{{{1}}}{{sla-pal2|{{{2}}}}}ěmi<!--
-->}}<!--
--><includeonly><!--
-->{{#ifeq:{{pagename}}|{{{1}}}{{{2}}}ъ<!--
-->|<!--
--><!--
-->}}<!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
gtn4wc4tschhmf700in1cye9ddxv4j7
ထာမ်ပလိက်:sla-decl-pron-hard/documentation
10
297567
399882
2026-07-23T01:26:00Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. --> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်|hard]]"
399882
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>
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်|hard]]
62cnowfajlhmvk4x2wraavmj6r5rime
ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဂမၠိုၚ်
14
297568
399883
2026-07-23T01:27:18Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]"
399883
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏသဗ္ဗနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
p8os89qkclt3zexchjdwm026t9h73sz
ထာမ်ပလိက်:sla-decl-pron-table
10
297569
399884
2026-07-23T01:42:07Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|sla-pro|{{{1}}}}}|palette=blue|tall=yes}} ! ကိုန်ဨကဝုစ် ! ပုလ္လိၚ် ! ဣတ္တိလိၚ် ! နပုလ္လိၚ် |- ! ''မဒုၚ်ယၟု'' | {{lang|sla-pro|{{{1}}}}} | {{lang|sla-pro|{{{7}}}}} | {{lang|sla-pro|{{{13}}}}} |- ! ''ကမ္မကာရက''..."
399884
wikitext
text/x-wiki
<includeonly>{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{m|sla-pro|{{{1}}}}}|palette=blue|tall=yes}}
! ကိုန်ဨကဝုစ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! ''မဒုၚ်ယၟု''
| {{lang|sla-pro|{{{1}}}}}
| {{lang|sla-pro|{{{7}}}}}
| {{lang|sla-pro|{{{13}}}}}
|-
! ''ကမ္မကာရက''
| {{lang|sla-pro|{{{2}}}}}
| {{lang|sla-pro|{{{8}}}}}
| {{lang|sla-pro|{{{14}}}}}
|-
! ''ဗဳဇဂကူ''
| {{lang|sla-pro|{{{3}}}}}
| {{lang|sla-pro|{{{9}}}}}
| {{lang|sla-pro|{{{15}}}}}
|-
! ''ခၞံဗဒှ်ဌာန်မတန်တဴ''
| {{lang|sla-pro|{{{4}}}}}
| {{lang|sla-pro|{{{10}}}}}
| {{lang|sla-pro|{{{16}}}}}
|-
! ''ပြကမ္မကာရက''
| {{lang|sla-pro|{{{5}}}}}
| {{lang|sla-pro|{{{11}}}}}
| {{lang|sla-pro|{{{17}}}}}
|-
! ''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်''
| {{lang|sla-pro|{{{6}}}}}
| {{lang|sla-pro|{{{12}}}}}
| {{lang|sla-pro|{{{18}}}}}
|-
! ၜါလ္ပာ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! ''ပရေၚ်ပ္တိုန်စရၚ်ယၟု''
| {{lang|sla-pro|{{{19}}}}}
| {{lang|sla-pro|{{{25}}}}}
| {{lang|sla-pro|{{{31}}}}}
|-
! ''ကမ္မကာရက''
| {{lang|sla-pro|{{{20}}}}}
| {{lang|sla-pro|{{{26}}}}}
| {{lang|sla-pro|{{{32}}}}}
|-
! ''ဗဳဇဂကူ''
| {{lang|sla-pro|{{{21}}}}}
| {{lang|sla-pro|{{{27}}}}}
| {{lang|sla-pro|{{{33}}}}}
|-
! ''ခၞံဗဒှ်ဌာန်မတန်တဴ''
| {{lang|sla-pro|{{{22}}}}}
| {{lang|sla-pro|{{{28}}}}}
| {{lang|sla-pro|{{{34}}}}}
|-
! ''ပြကမ္မကာရက''
| {{lang|sla-pro|{{{23}}}}}
| {{lang|sla-pro|{{{29}}}}}
| {{lang|sla-pro|{{{35}}}}}
|-
! ''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်''
| {{lang|sla-pro|{{{24}}}}}
| {{lang|sla-pro|{{{30}}}}}
| {{lang|sla-pro|{{{36}}}}}
|-
! ကိုန်ဗဟုဝစ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! ''မဒုၚ်ယၟု''
| {{lang|sla-pro|{{{37}}}}}
| {{lang|sla-pro|{{{43}}}}}
| {{lang|sla-pro|{{{49}}}}}
|-
! ''ကမ္မကာရက''
| {{lang|sla-pro|{{{38}}}}}
| {{lang|sla-pro|{{{44}}}}}
| {{lang|sla-pro|{{{50}}}}}
|-
! ''ဗဳဇဂကူ''
| {{lang|sla-pro|{{{39}}}}}
| {{lang|sla-pro|{{{45}}}}}
| {{lang|sla-pro|{{{51}}}}}
|-
! ''ခၞံဗဒှ်ဌာန်မတန်တဴ''
| {{lang|sla-pro|{{{40}}}}}
| {{lang|sla-pro|{{{46}}}}}
| {{lang|sla-pro|{{{52}}}}}
|-
! ''ပြကမ္မကာရက''
| {{lang|sla-pro|{{{41}}}}}
| {{lang|sla-pro|{{{47}}}}}
| {{lang|sla-pro|{{{53}}}}}
|-
! ''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်''
| {{lang|sla-pro|{{{42}}}}}
| {{lang|sla-pro|{{{48}}}}}
| {{lang|sla-pro|{{{54}}}}}
{{inflection-table-bottom}}</includeonly><noinclude>{{tcat|prondecl:*}}</noinclude>
osjq64pz3orz6zxnkxhbr2rw5rw8xfo
ထာမ်ပလိက်:sla-decl-adj-hard
10
297570
399885
2026-07-23T01:45:17Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{inflection-table-block-top}} {{#if:{{{noindef|}}}||{{sla-decl-adj-table<!-- -->|title={{{title|Indefinite declension of ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!-- Singular -->|{{{1}}}{{{2}}}ъ<!-- -->|{{{1}}}{{{2}}}ъ<!-- -->|{{{1}}}{{{2}}}a<!-- -->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!-- -->|{{{1}}}{{{2}}}u<!-- -->|{{{1}}}{{{2}}}omь<!-- -->|{{{..."
399885
wikitext
text/x-wiki
{{inflection-table-block-top}}
{{#if:{{{noindef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|Indefinite declension of ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{sla-pal1|{{{2}}}}}e<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ǫ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}ojǫ<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{{2}}}o<!--
Dual
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}axъ<!--
-->|{{{1}}}{{{2}}}amъ<!--
-->|{{{1}}}{{{2}}}ami<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->}}}}<!--
-->{{#if:{{{nodef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|Definite declension of ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}oje<!--
Dual
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}aja<!--
-->}}}}<!--
-->{{inflection-table-block-bottom}}<!--
--><includeonly><!--
--><!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
fh0ke3mc39ducp8gfocacwwsb8ri9yy
399889
399885
2026-07-23T02:15:46Z
咽頭べさ
33
399889
wikitext
text/x-wiki
{{inflection-table-block-top}}
{{#if:{{{noindef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|ပရေၚ်လဟုတ်စှ်ေဟွံချိုတ်ပၠိုတ်မဆေၚ်စပ်ကဵု ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{sla-pal1|{{{2}}}}}e<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ǫ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}ojǫ<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{{2}}}o<!--
Dual
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}axъ<!--
-->|{{{1}}}{{{2}}}amъ<!--
-->|{{{1}}}{{{2}}}ami<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->}}}}<!--
-->{{#if:{{{nodef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|Definite declension of ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}oje<!--
Dual
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}aja<!--
-->}}}}<!--
-->{{inflection-table-block-bottom}}<!--
--><includeonly><!--
--><!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
t4fqbo9r1sw0bmxx193xypu0wm2umun
399890
399889
2026-07-23T02:17:02Z
咽頭べさ
33
399890
wikitext
text/x-wiki
{{inflection-table-block-top}}
{{#if:{{{noindef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|ပရေၚ်လဟုတ်စှ်ေဟွံချိုတ်ပၠိုတ်မဆေၚ်စပ်ကဵု ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{sla-pal1|{{{2}}}}}e<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ǫ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}ojǫ<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}o<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}omь<!--
-->|{{{1}}}{{{2}}}o<!--
Dual
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{{2}}}ama<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}u<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{{2}}}oma<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ě<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}i<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{{2}}}axъ<!--
-->|{{{1}}}{{{2}}}amъ<!--
-->|{{{1}}}{{{2}}}ami<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}a<!--
-->|{{{1}}}{{{2}}}ъ<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěxъ<!--
-->|{{{1}}}{{{2}}}omъ<!--
-->|{{{1}}}{{{2}}}y<!--
-->|{{{1}}}{{{2}}}a<!--
-->}}}}<!--
-->{{#if:{{{nodef|}}}||{{sla-decl-adj-table<!--
-->|title={{{title|ပရေၚ်လဟုတ်စှ်ေမချိုတ်ပၠိုတ်မဆေၚ်စပ်ကဵု ''*{{pagename}}'' (hard{{#switch:{{{ap|}}}|a=, accent paradigm a|b=, accent paradigm b|c=, accent paradigm c}})}}}<!--
Singular
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}ъjь<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}ǫjǫ<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}oje<!--
-->|{{{1}}}{{{2}}}ajego<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ějemь<!--
-->|{{{1}}}{{{2}}}ujemu<!--
-->|{{{1}}}{{{2}}}yjimь<!--
-->|{{{1}}}{{{2}}}oje<!--
Dual
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}uju<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{{2}}}yjima<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}ěji<!--
Plural
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{sla-pal2|{{{2}}}}}iji<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}yję̇<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}aja<!--
-->|{{{1}}}{{{2}}}ъjixъ<!--
-->|{{{1}}}{{{2}}}yjixъ<!--
-->|{{{1}}}{{{2}}}yjimъ<!--
-->|{{{1}}}{{{2}}}yjimi<!--
-->|{{{1}}}{{{2}}}aja<!--
-->}}}}<!--
-->{{inflection-table-block-bottom}}<!--
--><includeonly><!--
--><!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
ronlk9tnzzmh3hbbdz8gamskafrssge
ထာမ်ပလိက်:sla-decl-adj-hard/documentation
10
297571
399886
2026-07-23T01:46:42Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. --> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်|hard]]"
399886
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>
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်|hard]]
pd0i33ibcfe2ym2sv5ngupjvpiuz5z3
ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဂမၠိုၚ်
14
297572
399887
2026-07-23T01:47:53Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]"
399887
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်သလာဗေတ်-အခိုက်ကၞာအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမဝိသေသနဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
q1u8bv7ay7n4qdtixi65hq8zpk5n09j
ထာမ်ပလိက်:sla-decl-adj-table
10
297573
399888
2026-07-23T02:11:11Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{inflection-table-top|title={{{title|မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''*{{pagename}}''}}}|palette=blue|tall=yes}} ! class="outer" | ကိုန်ဨကဝုစ် ! ပုလ္လိၚ် ! ဣတ္တိလိၚ် ! နပုလ္လိၚ် |- ! မဒုၚ်ယၟု | {{l-self|sla-pro|*{{{1}}}}} | {{l-self|sla-pro|*{{{8}}}}} | {{l-self|sla-pro|*{{{15}}}}} |- ! ဗဳဇဂ..."
399888
wikitext
text/x-wiki
{{inflection-table-top|title={{{title|မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု ''*{{pagename}}''}}}|palette=blue|tall=yes}}
! class="outer" | ကိုန်ဨကဝုစ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! မဒုၚ်ယၟု
| {{l-self|sla-pro|*{{{1}}}}}
| {{l-self|sla-pro|*{{{8}}}}}
| {{l-self|sla-pro|*{{{15}}}}}
|-
! ဗဳဇဂကူ
| {{l-self|sla-pro|*{{{3}}}}}
| {{l-self|sla-pro|*{{{10}}}}}
| {{l-self|sla-pro|*{{{17}}}}}
|-
! ပြကမ္မကာရက
| {{l-self|sla-pro|*{{{5}}}}}
| {{l-self|sla-pro|*{{{12}}}}}
| {{l-self|sla-pro|*{{{19}}}}}
|-
! ကမ္မကာရက
| {{l-self|sla-pro|*{{{2}}}}}
| {{l-self|sla-pro|*{{{9}}}}}
| {{l-self|sla-pro|*{{{16}}}}}
|-
!တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {{l-self|sla-pro|*{{{6}}}}}
| {{l-self|sla-pro|*{{{13}}}}}
| {{l-self|sla-pro|*{{{20}}}}}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| {{l-self|sla-pro|*{{{4}}}}}
| {{l-self|sla-pro|*{{{11}}}}}
| {{l-self|sla-pro|*{{{18}}}}}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| {{l-self|sla-pro|*{{{7}}}}}
| {{l-self|sla-pro|*{{{14}}}}}
| {{l-self|sla-pro|*{{{21}}}}}
|-
! class="outer" | ၜါလ္ပာ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! မဒုၚ်ယၟု
| {{l-self|sla-pro|*{{{22}}}}}
| {{l-self|sla-pro|*{{{29}}}}}
| {{l-self|sla-pro|*{{{36}}}}}
|-
! ဗဳဇဂကူ
| {{l-self|sla-pro|*{{{24}}}}}
| {{l-self|sla-pro|*{{{31}}}}}
| {{l-self|sla-pro|*{{{38}}}}}
|-
! ပြကမ္မကာရက
| {{l-self|sla-pro|*{{{26}}}}}
| {{l-self|sla-pro|*{{{33}}}}}
| {{l-self|sla-pro|*{{{40}}}}}
|-
! ကမ္မကာရက
| {{l-self|sla-pro|*{{{23}}}}}
| {{l-self|sla-pro|*{{{30}}}}}
| {{l-self|sla-pro|*{{{37}}}}}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {{l-self|sla-pro|*{{{27}}}}}
| {{l-self|sla-pro|*{{{34}}}}}
| {{l-self|sla-pro|*{{{41}}}}}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| {{l-self|sla-pro|*{{{25}}}}}
| {{l-self|sla-pro|*{{{32}}}}}
| {{l-self|sla-pro|*{{{39}}}}}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| {{l-self|sla-pro|*{{{28}}}}}
| {{l-self|sla-pro|*{{{35}}}}}
| {{l-self|sla-pro|*{{{42}}}}}
|-
! class="outer" | ကိုန်ဗဟုဝစ်
! ပုလ္လိၚ်
! ဣတ္တိလိၚ်
! နပုလ္လိၚ်
|-
! မဒုၚ်ယၟု
| {{l-self|sla-pro|*{{{43}}}}}
| {{l-self|sla-pro|*{{{50}}}}}
| {{l-self|sla-pro|*{{{57}}}}}
|-
! ဗဳဇဂကူ
| {{l-self|sla-pro|*{{{45}}}}}
| {{l-self|sla-pro|*{{{52}}}}}
| {{l-self|sla-pro|*{{{59}}}}}
|-
! ပြကမ္မကာရက
| {{l-self|sla-pro|*{{{47}}}}}
| {{l-self|sla-pro|*{{{54}}}}}
| {{l-self|sla-pro|*{{{61}}}}}
|-
! ကမ္မကာရက
| {{l-self|sla-pro|*{{{44}}}}}
| {{l-self|sla-pro|*{{{51}}}}}
| {{l-self|sla-pro|*{{{58}}}}}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {{l-self|sla-pro|*{{{48}}}}}
| {{l-self|sla-pro|*{{{55}}}}}
| {{l-self|sla-pro|*{{{62}}}}}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| {{l-self|sla-pro|*{{{46}}}}}
| {{l-self|sla-pro|*{{{53}}}}}
| {{l-self|sla-pro|*{{{60}}}}}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| {{l-self|sla-pro|*{{{49}}}}}
| {{l-self|sla-pro|*{{{56}}}}}
| {{l-self|sla-pro|*{{{63}}}}}
{{inflection-table-bottom}}<!--
--><noinclude>{{tcat|adecl:*}}</noinclude>
d0kaxvw573sv23ookahd73ctcnrh4eb
злобно
0
297574
399891
2026-07-23T02:30:01Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ===ဗွဟ်ရမ္သာၚ်=== * {{mk-IPA}} ===ကြိယာဝိသေသန=== {{mk-adv}} # ဗွဲမယုတ်မာကြံကြ၊ ပွမဂၞံၚ်ဂၞာတ်၊ ဗွဲမယုတ်မာ။ ==ရုဿျှာ== {{was wotd|၂၀၂၆|ဂျူလာင်|၂၃}} ===ဗွဟ်ရမ္သာၚ်=== * {{ru-IPA|зло́б..."
399891
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
===ဗွဟ်ရမ္သာၚ်===
* {{mk-IPA}}
===ကြိယာဝိသေသန===
{{mk-adv}}
# ဗွဲမယုတ်မာကြံကြ၊ ပွမဂၞံၚ်ဂၞာတ်၊ ဗွဲမယုတ်မာ။
==ရုဿျှာ==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၃}}
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́бно}}
* {{audio|ru|LL-Q7737 (rus)-Rominf-злобно.wav}}
===ကြိယာဝိသေသန===
{{ru-adv|зло́бно}}
# ဗွဲမယုတ်မာကြံကြ၊ ပွမဂၞံၚ်ဂၞာတ်၊ ဗွဲမယုတ်မာ။
# ဗွဲမထေဲပၞတ်၊ ဗွဲမသ္ဒးက္ဍုဟ်မၠေံခိုဟ်။
====နာမဝိသေသန====
{{head|ru|adjective form|head=зло́бно}}
# {{inflection of|ru|зло́бный||short|n|s}}
9vpnaqw65xo8653rktko5hhxbj9qy7r
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၃
4
297575
399892
2026-07-23T02:31:13Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|злобно|ကြိယာဝိသေသန| ဗွဲမယုတ်မာကြံကြ၊ ပွမဂၞံၚ်ဂၞာတ်၊ ဗွဲမယုတ်မာ။ # ဗွဲမထေဲပၞတ်၊ ဗွဲမသ္ဒးက္ဍုဟ်မၠေံခိုဟ်။|audio=LL-Q7737 (rus)-Rominf-злобно.wav|ဂျူလာင်|၂၃}}"
399892
wikitext
text/x-wiki
{{WOTD|злобно|ကြိယာဝိသေသန| ဗွဲမယုတ်မာကြံကြ၊ ပွမဂၞံၚ်ဂၞာတ်၊ ဗွဲမယုတ်မာ။
# ဗွဲမထေဲပၞတ်၊ ဗွဲမသ္ဒးက္ဍုဟ်မၠေံခိုဟ်။|audio=LL-Q7737 (rus)-Rominf-злобно.wav|ဂျူလာင်|၂၃}}
obovhmc7ewjjs7xc8b63rx7wla4zg6e
позлобно
0
297576
399893
2026-07-23T02:34:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ===ကြိယာဝိသေသန=== {{head|mk|ဗီုပြၚ်ကြိယာဝိသေသန}} # {{comparative of|mk|злобно}}"
399893
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
===ကြိယာဝိသေသန===
{{head|mk|ဗီုပြၚ်ကြိယာဝိသေသန}}
# {{comparative of|mk|злобно}}
k7wprc43dy9z5igisajnghs1oitdnz2
ကဏ္ဍ:ဗီုပြၚ်ကြိယာဝိသေသနမက်သဳဒဝ်နဳယျာဂမၠိုၚ်
14
297577
399894
2026-07-23T02:37:31Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာမက်သဳဒဝ်နဳယျာ]]"
399894
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာမက်သဳဒဝ်နဳယျာ]]
pn8i4qxbw2vc0y25bi3bs2tgytwo1yw
најзлобно
0
297578
399895
2026-07-23T02:39:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==မက်သဳဒဝ်နဳယျာ== ===ကြိယာဝိသေသန=== {{head|mk|ဗီုပြၚ်ကြိယာဝိသေသန}} # {{superlative of|mk|злобно}}"
399895
wikitext
text/x-wiki
==မက်သဳဒဝ်နဳယျာ==
===ကြိယာဝိသေသန===
{{head|mk|ဗီုပြၚ်ကြိယာဝိသေသန}}
# {{superlative of|mk|злобно}}
hrxuqlg0y87eayhm3e6cm6o6iibbbgh
злобность
0
297579
399896
2026-07-23T02:40:42Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{superlative of|ru|злобный}}"
399896
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{superlative of|ru|злобный}}
hjwg57b14nglaatevzxp3h55v4q5upm
злобненький
0
297580
399897
2026-07-23T02:41:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ====နာမဝိသေသန==== {{head|ru|ဗီုပြၚ်နာမဝိသေသန}} # {{superlative of|ru|злобный}}"
399897
wikitext
text/x-wiki
==ရုဿျှာ==
====နာမဝိသေသန====
{{head|ru|ဗီုပြၚ်နာမဝိသေသန}}
# {{superlative of|ru|злобный}}
hjwg57b14nglaatevzxp3h55v4q5upm
зълоба
0
297581
399898
2026-07-23T02:44:59Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==သလာဗေတ်ဗၟံက်တြေံ== ===နာမ်=== {{cu-noun|f}} # မယုတ်မာ၊ မယုတ်မာကြံကြ။ ====လဟုတ်စှ်ေ==== {{cu-decl-noun-a|зъло|б}} ===မဒုၚ်လွဳစ=== * {{desc|ru|злоба}} * {{desc|bg|злоба}}"
399898
wikitext
text/x-wiki
==သလာဗေတ်ဗၟံက်တြေံ==
===နာမ်===
{{cu-noun|f}}
# မယုတ်မာ၊ မယုတ်မာကြံကြ။
====လဟုတ်စှ်ေ====
{{cu-decl-noun-a|зъло|б}}
===မဒုၚ်လွဳစ===
* {{desc|ru|злоба}}
* {{desc|bg|злоба}}
5jx3a8jqpslcqng9lmfo05j4aji5070
ထာမ်ပလိက်:cu-decl-noun-a
10
297582
399899
2026-07-23T02:46:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|warn}}<!-- Validate template parameters -->{{#ifeq:{{bestscript|cu|{{{1|}}}}}|Glag|{{cu-decl-noun|type=hard a-stem|head={{{head|}}} <!-- singular --> |{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⰰ}} |{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱏⰹ}} |{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}} |{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱘ}} |{{#switch..."
399899
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
-->{{#ifeq:{{bestscript|cu|{{{1|}}}}}|Glag|{{cu-decl-noun|type=hard a-stem|head={{{head|}}}
<!-- singular -->
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⰰ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱏⰹ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱘ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱁⱙ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ⱁ}}
<!-- dual -->
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ⱆ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ⰰⰿⰰ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ⰰⰿⰰ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ⱆ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|ⰽ=ⱌ|ⰳ=ⰷ|ⱈ=ⱄ|{{{2}}}}}ⱑ}}
<!-- plural -->
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⱏⰹ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⱏ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⰰⰿⱏ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⱏⰹ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⰰⰿⰻ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⰰⱈⱏ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ⱏⰹ}}
}}|{{cu-decl-noun|type=hard a-stem|head={{{head|}}}
<!-- singular -->
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}а}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ꙑ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{#switch:{{{2}}}|к=ц|г=ѕ|х=с|{{{2}}}}}ѣ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}ѫ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}оѭ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{#switch:{{{2}}}|к=ц|г=ѕ|х=с|{{{2}}}}}ѣ}}
|{{#switch:{{{n|}}}|dl|pl=-|{{{1}}}{{{2}}}о}}
<!-- dual -->
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|к=ц|г=ѕ|х=с|{{{2}}}}}ѣ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}оу}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ама}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|к=ц|г=ѕ|х=с|{{{2}}}}}ѣ}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}ама}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{{2}}}оу}}
|{{#switch:{{{n|}}}|sg|pl=-|{{{1}}}{{#switch:{{{2}}}|к=ц|г=ѕ|х=с|{{{2}}}}}ѣ}}
<!-- plural -->
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ꙑ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ъ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}амъ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ꙑ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ами}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ахъ}}
|{{#switch:{{{n|}}}|sg|dl=-|{{{1}}}{{{2}}}ꙑ}}
}}}}<includeonly>{{cln|cu|hard a-stem nouns|hard {{#switch:{{{g}}}|m=masculine|feminine}} a-stem nouns|{{#switch:{{{n}}}|sg=singularia tantum|dl=dualia tantum|pl=pluralia tantum}}}}</includeonly><noinclude>{{documentation}}{{tcat|ndecl:Ⅲ}}</noinclude>
52ag0qguzzm1xqizhhn2tlq3gr2nmfg
ထာမ်ပလိက်:cu-decl-noun-a/documentation
10
297583
399900
2026-07-23T02:48:39Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} ==Usage== Template used to generate declension for masculine and feminine hard a-stem nouns. It also supports Glagolitic script. ==Parameters== * {{para|1|req=1}} - word without two last letters * {{para|2|req=1}} - penultimate letter * {{para|n|opt=1}} - shows only selected number (<code>sg</code>, <code>dl</code>, <code>pl</code>) ==Example== * Code: <code><nowiki>{{cu-decl-noun-a|во|..."
399900
wikitext
text/x-wiki
{{documentation subpage}}
==Usage==
Template used to generate declension for masculine and feminine hard a-stem nouns. It also supports Glagolitic script.
==Parameters==
* {{para|1|req=1}} - word without two last letters
* {{para|2|req=1}} - penultimate letter
* {{para|n|opt=1}} - shows only selected number (<code>sg</code>, <code>dl</code>, <code>pl</code>)
==Example==
* Code:
<code><nowiki>{{cu-decl-noun-a|во|д}}</nowiki></code>
* Effect:
{{cu-decl-noun-a|во|д}}
bm0x2aame4y8s02dpt052jo4m4xitgq
ထာမ်ပလိက်:cu-decl-noun
10
297584
399901
2026-07-23T02:53:15Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{lang|cu|{{#if:{{{head|}}}|{{{head}}}|{{pagename}}}}}} {{#if:{{{type|}}}|({{{type}}})|}}|palette=blue|tall=yes}} ! ! ကိုန်ဨကဝုစ် ! ၜါလ္ပာ် ! ကိုန်ဗဟုဝစ် |- ! မဒုၚ်ယၟု | {{cu-table entry|{{{1}}}}} | {{cu-table entry|{{{8}}}}} | {{cu-table entry|{{{15}}}}} |..."
399901
wikitext
text/x-wiki
{{inflection-table-top|title=မလဟုတ်စှ်ေဆေၚ်စပ်ကဵု {{lang|cu|{{#if:{{{head|}}}|{{{head}}}|{{pagename}}}}}} {{#if:{{{type|}}}|({{{type}}})|}}|palette=blue|tall=yes}}
!
! ကိုန်ဨကဝုစ်
! ၜါလ္ပာ်
! ကိုန်ဗဟုဝစ်
|-
! မဒုၚ်ယၟု
| {{cu-table entry|{{{1}}}}}
| {{cu-table entry|{{{8}}}}}
| {{cu-table entry|{{{15}}}}}
|-
! ဗဳဇဂကူ
| {{cu-table entry|{{{2}}}}}
| {{cu-table entry|{{{9}}}}}
| {{cu-table entry|{{{16}}}}}
|-
! ပြကမ္မကာရက
| {{cu-table entry|{{{3}}}}}
| {{cu-table entry|{{{10}}}}}
| {{cu-table entry|{{{17}}}}}
|-
! ကမ္မကာရက
| {{cu-table entry|{{{4}}}}}
| {{cu-table entry|{{{11}}}}}
| {{cu-table entry|{{{18}}}}}
|-
! တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
| {{cu-table entry|{{{5}}}}}
| {{cu-table entry|{{{12}}}}}
| {{cu-table entry|{{{19}}}}}
|-
! ခၞံဗဒှ်ဌာန်မတန်တဴ
| {{cu-table entry|{{{6}}}}}
| {{cu-table entry|{{{13}}}}}
| {{cu-table entry|{{{20}}}}}
|-
! ပရေၚ်ဂယိုၚ်လမျီု
| {{cu-table entry|{{{7}}}}}
| {{cu-table entry|{{{14}}}}}
| {{cu-table entry|{{{21}}}}}
{{inflection-table-bottom}}<noinclude>{{tcat|ndecl:*noun}}</noinclude>
39fxpxgadumns50hng4yw40t2p2ldn7
ထာမ်ပလိက်:cu-table entry
10
297585
399902
2026-07-23T02:55:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{lang|cu|{{#invoke:table tools|linkify_entry|lang=cu<noinclude>|пѫтьмь,пѫтемь</noinclude>}}}}<br/><span style="color: var(--wikt-palette-grey-8,#888)">{{#invoke:table tools|translit_entry|lang=cu<noinclude>|пѫтьмь,пѫтемь</noinclude>}}</span><noinclude>{{documentation}}[[ကဏ္ဍ:ထာမ်ပလိက်မသ္ပထၜာတ်လဝ်-အဝ်တဝ်နူကဵု SurjectionBot]..."
399902
wikitext
text/x-wiki
{{lang|cu|{{#invoke:table tools|linkify_entry|lang=cu<noinclude>|пѫтьмь,пѫтемь</noinclude>}}}}<br/><span style="color: var(--wikt-palette-grey-8,#888)">{{#invoke:table tools|translit_entry|lang=cu<noinclude>|пѫтьмь,пѫтемь</noinclude>}}</span><noinclude>{{documentation}}[[ကဏ္ဍ:ထာမ်ပလိက်မသ္ပထၜာတ်လဝ်-အဝ်တဝ်နူကဵု SurjectionBot]]</noinclude>
bebveqn8uxg5k6qcbppifddle163j0l
ထာမ်ပလိက်:cu-table entry/documentation
10
297586
399903
2026-07-23T03:01:53Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. --> <includeonly> [[ကဏ္ဍ:ထာမ်ပလိက်ခရေတ်သလာဗဝ်နေတ်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်|table entry]] </includeonly>"
399903
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>
[[ကဏ္ဍ:ထာမ်ပလိက်ခရေတ်သလာဗဝ်နေတ်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်|table entry]]
</includeonly>
98r8xwophlado5llrtp69z60wi7ovmn
злобы
0
297587
399904
2026-07-23T03:38:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ===ဗွဟ်ရမ္သာၚ်=== * {{ru-IPA|зло́бы}} ===နာမ်=== {{head|ru|noun form|head=зло́бы|g=f-in|g2=f-in-p}} # {{inflection of|ru|зло́ба||gen|s|;|nom//acc|p}}"
399904
wikitext
text/x-wiki
==ရုဿျှာ==
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA|зло́бы}}
===နာမ်===
{{head|ru|noun form|head=зло́бы|g=f-in|g2=f-in-p}}
# {{inflection of|ru|зло́ба||gen|s|;|nom//acc|p}}
0pmjlr3aiuug9w35qsr829mjoyviwxo
злоб
0
297588
399905
2026-07-23T03:39:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ရုဿျှာ== ===ဗွဟ်ရမ္သာၚ်=== * {{ru-IPA}} ===နာမ်=== {{head|ru|noun form|g=f-in-p}} # {{inflection of|ru|зло́ба||gen|p}}"
399905
wikitext
text/x-wiki
==ရုဿျှာ==
===ဗွဟ်ရမ္သာၚ်===
* {{ru-IPA}}
===နာမ်===
{{head|ru|noun form|g=f-in-p}}
# {{inflection of|ru|зло́ба||gen|p}}
c4ub79a0ggwgp34fbzswpfph3vbl64i
zloba
0
297589
399906
2026-07-23T03:46:20Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|złoba|złobą|żłoba|злоба}} ==ချက်ခ်== ===နိရုတ်=== {{inh+|cs|zlw-ocs|zloba}}၊ နူကဵုဝေါဟာ {{inh|cs|sla-pro|*zъloba}} ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA}} ===နာမ်=== {{cs-noun|f}} # မနောဒေါသ၊ ဒေါသ၊ မနောဒေါသတိတ်။ ====လဟုတ်စှ်ေ==== {{cs-ndecl|f}} ==သာဗ..."
399906
wikitext
text/x-wiki
{{also|złoba|złobą|żłoba|злоба}}
==ချက်ခ်==
===နိရုတ်===
{{inh+|cs|zlw-ocs|zloba}}၊ နူကဵုဝေါဟာ {{inh|cs|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{cs-IPA}}
===နာမ်===
{{cs-noun|f}}
# မနောဒေါသ၊ ဒေါသ၊ မနောဒေါသတိတ်။
====လဟုတ်စှ်ေ====
{{cs-ndecl|f}}
==သာဗ်ခြဝ်ဨရှဳယာန်==
===နိရုတ်===
{{inh+|sh|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
* {{sh-IPA|zlòba}}
* {{hyphenation|sh|zlo|ba}}
===နာမ်===
{{sh-noun|zlòba|f}}
# စိုတ်ပစ္ဆရိယ၊ မဂၠာဲသၞ။
====လဟုတ်စှ်ေ====
{{sh-decl-noun-unc
|zloba
|zlobe
|zlobi
|zlobu
|zlobo
|zlobi
|zlobom
}}
cfbwmfye09ohfoaxfoxtu81mt6gd8xj
żłoba
0
297590
399907
2026-07-23T03:48:28Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zloba|złoba|złobą}} ==ပဝ်လာန်== ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr}} ===နာမ်=== {{head|pl|noun form|g=m-in}} # {{inflection of|pl|żłób||gen|s}} ===နာမ်=== {{head|pl|noun form|g=m-pr}} # {{inflection of|pl|żłób||gen//acc|s}}"
399907
wikitext
text/x-wiki
{{also|zloba|złoba|złobą}}
==ပဝ်လာန်==
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr}}
===နာမ်===
{{head|pl|noun form|g=m-in}}
# {{inflection of|pl|żłób||gen|s}}
===နာမ်===
{{head|pl|noun form|g=m-pr}}
# {{inflection of|pl|żłób||gen//acc|s}}
3v3f4my1gz6h9tmjzeiw86qu8om49rk
żłób
0
297591
399908
2026-07-23T04:45:53Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zlob|żlób|żłōb|żłób}} ==ကသှုဗဳယာန်== ===ဗွဟ်ရမ္သာၚ်=== {{csb-pr}} ===နာမ်=== {{csb-noun|m-in|dim=żłóbk|aug=żłobiszcze}} # ဍာ်ကရံက်။ # ဂရာ်ဇြဟ်။ ===နာမ် ၂ === {{csb-noun|m-pr}} # မၞိဟ်ကဆံၚ်သဝ်။ ==ပဝ်လာန်တြေံ== ===ဗွဟ်ရမ္သာၚ်===..."
399908
wikitext
text/x-wiki
{{also|zlob|żlób|żłōb|żłób}}
==ကသှုဗဳယာန်==
===ဗွဟ်ရမ္သာၚ်===
{{csb-pr}}
===နာမ်===
{{csb-noun|m-in|dim=żłóbk|aug=żłobiszcze}}
# ဍာ်ကရံက်။
# ဂရာ်ဇြဟ်။
===နာမ် ၂ ===
{{csb-noun|m-pr}}
# မၞိဟ်ကဆံၚ်သဝ်။
==ပဝ်လာန်တြေံ==
===ဗွဟ်ရမ္သာၚ်===
* {{zlw-opl-IPA}}
===နာမ်===
{{zlw-opl-noun|m-in|dim=żłobek}}
# ဍာ်ကရံက်။
=====လဟုတ်စှ်ေ=====
{{zlw-opl-decl-noun
|żłób|-|żłoby
|-|-|-
|żłobowi|-|-
|żłób|-|żłoby
|-|-|-
|żłobie|-|-
|-|-|-}}
===မဒုၚ်လွဳစ===
* {{desc|pl|żłób|id=trough}}
* {{desc|szl|żłōb}}
==ပဝ်လာန်==
{{wp|pl:}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr|a=LL-Q809 (pol)-Nostrix-#.wav;LL-Q809 (pol)-Olaf-#.wav|mp=#|krk=#}}
===ပွံၚ်နဲတၞဟ်===
* {{alt|pl|żłob||Middle Polish}}
===နာမ်===
{{pl-noun|m-in|dim=żłóbek}}
# ဍာ်ကရံက်။
#: {{syn|pl|koryto}}
=====လဟုတ်စှ်ေ=====
{{pl-decl-noun-m-in|gens=żłobu/żłoba}}
===နာမ် ၂ ===
{{pl-noun|m-pr}}
# ဍာ်ကရံက်။
=====လဟုတ်စှ်ေ=====
{{pl-decl-noun-m-pr|żło|b|noms=żłób|nomp=[[żłobi]]/[[żłobowie]]/[[żłoby]] (deprecative)}}
===မဒုၚ်လွဳစ===
* {{desc|ru|жлоб|bor=1}}
* {{desc|yi|זשלאָב|bor=1}}
** {{desc|en|schlub|bor=1}}
===ကြိယာ===
{{head|pl|verb form}}
# {{inflection of|pl|żłobić||2|s|imp}}
4ocmtsl450tawylpqfhx8o050xys0cj
399919
399908
2026-07-23T05:39:02Z
咽頭べさ
33
399919
wikitext
text/x-wiki
{{also|zlob|żlób|żłōb|żłób}}
==ကသှုဗဳယာန်==
===ဗွဟ်ရမ္သာၚ်===
{{csb-pr}}
===နာမ်===
{{csb-noun|m-in|dim=żłóbk|aug=żłobiszcze}}
# ဍာ်ကရံက်။
# ဂရာ်ဇြဟ်။
===နာမ် ၂ ===
{{csb-noun|m-pr}}
# မၞိဟ်ကဆံၚ်သဝ်။
==ပဝ်လာန်တြေံ==
===ဗွဟ်ရမ္သာၚ်===
* {{zlw-opl-IPA}}
===နာမ်===
{{zlw-opl-noun|m-in|dim=żłobek}}
# ဍာ်ကရံက်။
=====လဟုတ်စှ်ေ=====
{{zlw-opl-decl-noun
|żłób|-|żłoby
|-|-|-
|żłobowi|-|-
|żłób|-|żłoby
|-|-|-
|żłobie|-|-
|-|-|-}}
===မဒုၚ်လွဳစ===
* {{desc|pl|żłób|id=trough}}
* {{desc|szl|żłōb}}
==ပဝ်လာန်==
{{wp|pl:}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr|a=LL-Q809 (pol)-Nostrix-#.wav;LL-Q809 (pol)-Olaf-#.wav|mp=#|krk=#}}
===ပွံၚ်နဲတၞဟ်===
* {{alt|pl|żłob||Middle Polish}}
===နာမ်===
{{pl-noun|m-in|dim=żłóbek}}
# ဍာ်ကရံက်။
#: {{syn|pl|koryto}}
=====လဟုတ်စှ်ေ=====
{{pl-decl-noun-m-in|gens=żłobu/żłoba}}
===နာမ် ၂ ===
{{pl-noun|m-pr}}
# ဂၠုၚ်ကၠဵုစစၞ။
=====လဟုတ်စှ်ေ=====
{{pl-decl-noun-m-pr|żło|b|noms=żłób|nomp=[[żłobi]]/[[żłobowie]]/[[żłoby]] (deprecative)}}
===မဒုၚ်လွဳစ===
* {{desc|ru|жлоб|bor=1}}
* {{desc|yi|זשלאָב|bor=1}}
** {{desc|en|schlub|bor=1}}
===ကြိယာ===
{{head|pl|verb form}}
# {{inflection of|pl|żłobić||2|s|imp}}
kpz6qhe8yccs4p9kdc7mfjaqaarllme
ထာမ်ပလိက်:zlw-opl-decl-noun
10
297592
399909
2026-07-23T04:50:42Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:zlw-opl-noun|template_decl_manual|subst=<includeonly>{{subst:</includeonly>substcheck<includeonly>}}</includeonly>}}<noinclude>{{documentation}}</noinclude>"
399909
wikitext
text/x-wiki
{{#invoke:zlw-opl-noun|template_decl_manual|subst=<includeonly>{{subst:</includeonly>substcheck<includeonly>}}</includeonly>}}<noinclude>{{documentation}}</noinclude>
ro2pq18bpfqvglzuxh3esia3nn8xs4g
မဝ်ဂျူ:zlw-opl-noun
828
297593
399910
2026-07-23T05:18:23Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "local export = {} local m_links = require('Module:links') local m_g = require('Module:gender and number') local lang = require("Module:languages").getByCode("zlw-opl") -- case information local cases = { { key = "nom"; en = "မဒုၚ်ယၟု"; pl = "mianownik (kto? co?)" }, { key = "gen"; en = "ဗဳဇဂကူ"; pl = "dopełniacz (kogo? czego?)" }, { key = "dat"; en = "ပြကမ္မကာရက";..."
399910
Scribunto
text/plain
local export = {}
local m_links = require('Module:links')
local m_g = require('Module:gender and number')
local lang = require("Module:languages").getByCode("zlw-opl")
-- 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 Old Polish nouns
local noun_dual_cols = {
{ key = "s"; title = "ကိုန်ဨကဝုစ်" },
{ key = "d"; title = "ၜါလ္ပာ်" },
{ key = "p"; title = "ကိုန်ဗဟုဝစ်" },
}
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.title.getCurrentTitle().fullText
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 = ""
if word:sub(-string.len(" (archaic)")) == " (archaic)" then
word = (mw.text.split(word, "% %(archaic%)"))[1]
add_archaic = " (archaic)"
end
if word == title then
table.insert(items, ("[[%s]]"):format(word) .. add_archaic)
else
table.insert(items, ("[[%s#ပဝ်လာန်တြေံ|%s]]"):format(word, word) .. add_archaic)
end
end
return table.concat(items, "/")
end
end
local function linkify_info(declinfo, splitchars, nolinks)
local linked = {}
local title = mw.title.getCurrentTitle().fullText
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 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="zlw-opl" xml:lang="zlw-opl">%s</span>'):format(lemma)
local emwidth = width or guess_width(declinfo, cols)
--if preproc == "nowiki" then
-- declinfo = nowiki_info(declinfo)
--else
if preproc == "linkify" then
declinfo = linkify_info(declinfo, altsep, nolinks)
end
if cols and (#cols > 0) then
table.insert(result, '|-\n! style="background:var(--wikt-palette-blue-2,#d9ebff); width: 8em;" |\n')
for i, col in ipairs(cols) do
table.insert(result, ('! style="background:var(--wikt-palette-blue-2,#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-blue-1,#eff7ff);" 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
table.insert(result, ('| <span class="Latn" lang="zlw-opl" xml:lang="zlw-opl">%s</span>\n'):format(item))
end
end
end
local outtext = ([=[<div class="NavFrame" style="display: block;width: %uem;">
<div class="NavHead" style="background:var(--wikt-palette-blue-1,#eff7ff)" >%s</div>
<div class="NavContent">
{| style="background:var(--wikt-palette-grey-0,#F9F9F9); text-align:center; width: %uem; margin: 0;" class="inflection-table"
]=]):format(emwidth, title, emwidth) .. table.concat(result, "") .. "|}</div></div>"
if tantum == "s" then
outtext = outtext .. " "
elseif tantum == "p" then
outtext = outtext .. " "
end
return outtext
end
local function make_table_from_pargs(pargs, cols, tantum)
local width = pargs.width and tonumber(pargs.width)
local declinfo = {}
cols = override_col_titles(pargs.heads, cols or {})
for i = 1, #cases 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
function export.template_decl_manual(frame)
local pargs = frame:getParent().args
return make_table_from_pargs(pargs, noun_dual_cols, nil)
end
return export
jn563z6ryco2j1zmr3iz2uzk5fedlqy
ထာမ်ပလိက်:zlw-opl-decl-noun/documentation
10
297594
399911
2026-07-23T05:22:21Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> Declension table with dual number for Old Polish entries. ===Usage=== <pre> ====Declension==== {{zlw-opl-decl-noun ||| ||| ||| ||| ||| ||| ||| }} </pre> <includeonly> ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာ..."
399911
wikitext
text/x-wiki
{{documentation subpage}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
Declension table with dual number for Old Polish entries.
===Usage===
<pre>
====Declension====
{{zlw-opl-decl-noun
|||
|||
|||
|||
|||
|||
|||
}}
</pre>
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်| dual]]
</includeonly>
lamukxvwqtaym6lvyb3w42bcnw549fv
ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်
14
297595
399912
2026-07-23T05:24:10Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]"
399912
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]
k4jicarzdtbx7of83o00t4bqhbd6st8
ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်
14
297596
399913
2026-07-23T05:26:40Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]"
399913
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]
qfl71h24sywknd828ukxwznhesj5a40
မဝ်ဂျူ:zlw-opl-noun/documentation
828
297597
399914
2026-07-23T05:31:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly> {{module cat|zlw-opl}} </includeonly>"
399914
wikitext
text/x-wiki
<includeonly>
{{module cat|zlw-opl}}
</includeonly>
2ynja9rxd5qxaox6ha66xtk7jrjqpgh
399915
399914
2026-07-23T05:31:45Z
咽頭べさ
33
咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:zlw-opl-noun/doc]] ဇရေင် [[မဝ်ဂျူ:zlw-opl-noun/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင်
399914
wikitext
text/x-wiki
<includeonly>
{{module cat|zlw-opl}}
</includeonly>
2ynja9rxd5qxaox6ha66xtk7jrjqpgh
ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲပဝ်လာန်တြေံဂမၠိုၚ်
14
297598
399916
2026-07-23T05:33:27Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူပဝ်လာန်တြေံဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]]ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ..."
399916
wikitext
text/x-wiki
[[ကဏ္ဍ:မဝ်ဂျူပဝ်လာန်တြေံဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်တြေံအပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]
9s0agy3fq0hd9pworb5764xmpq508dv
ထာမ်ပလိက်:pl-decl-noun-m-pr
10
297599
399917
2026-07-23T05:36:13Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|m-pr}}<noinclude>{{documentation}}</noinclude>"
399917
wikitext
text/x-wiki
{{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|m-pr}}<noinclude>{{documentation}}</noinclude>
c8v2espyhjmvs9k8enbw9yfb5rw2svu
ထာမ်ပလိက်:pl-decl-noun-m-pr/documentation
10
297600
399918
2026-07-23T05:37:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> This declension table is for Polish <u>masculine personal</u> nouns. By default, the lemma is taken from the title of the current page, but this can be overridden with the parameter {{para|lemma}}. If parameters are omitted, it will automatically use the correct declension pattern based on the word ending: * Feminine-li..."
399918
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 personal</u> nouns.
By default, the lemma is taken from the title of the current page, but this can be overridden with the parameter {{para|lemma}}. If parameters are omitted, it will automatically use the correct declension pattern based on the word ending:
* Feminine-like declension in the singular when the noun ends in -a.
* Adjectival declension when the noun ends in -y or -i.
For all other endings, the template will guess where to split the word into the stem and ending, and handle some common vowel elisions (-ek, -iec, etc.)
===Usage===
<tt><nowiki>====Declension====</nowiki></tt><br>
<tt><nowiki>{{pl-decl-noun-m-pr|||}}</nowiki></tt>
The parameters are as follows.
* First parameter: '''word stem''' as used in the genitive singular form (optional)
* Second parameter: '''last consonant or consonant cluster''' of the word (optional)
** Use a cluster if it has irregular declension in the locative singular (e.g. palatalization of a consonant), such as sł, sm, sn, st, zd, zł, zm, zn. Otherwise use only the last consonant.
** If the last consonant is soft, use its iotted version: ci, dzi, ni, si, zi instead of ć, dź, ń, ś, ź. This matches the form in the genitive singular.
* Third parameter: '''nominative plural''' (optional)
* Fourth parameter: '''nominative singular''' (optional). Used when the genitive singular stem passed as the first parameter is different from the nominative singular stem, such as bóg/bog-, mąż/męż-, krawiec/krawc-.
* Fifth parameter: '''alternate form of the genitive plural''' (optional)
===Examples===
* profesor: {{temp|pl-decl-noun-m-pr|profeso|r|profesorowie}}
* mąż: {{temp|pl-decl-noun-m-pr|mę|ż|mężowie|mąż}}
* krawiec: {{temp|pl-decl-noun-m-pr|kraw|c|krawcy|krawiec}}
* policjant: {{temp|pl-decl-noun-m-pr|policjan|t}}
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်|masc-pers]]
</includeonly>
c9q27avlulh0fqgvwbpr9ni03h3hld1
ကဏ္ဍ:ကာရန်:ပဝ်လာန်/up
14
297601
399921
2026-07-23T05:51:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်န်|ပဝ်လာန်]] » :ကဏ္ဍ:..."
399921
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်န်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -up
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် [[ကာရန်:ပဝ်လာန်/up|-up]] ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|up]]
03u07cmw837g89jrk2uqszfz31loiae
399922
399921
2026-07-23T05:52:09Z
咽頭べさ
33
399922
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -up
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် [[ကာရန်:ပဝ်လာန်/up|-up]] ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|up]]
sns1kv304ki1fmkeo0ge9ddba2xh270
ကာရန်:ပဝ်လာန်/up
106
297602
399923
2026-07-23T05:53:19Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|pl|u|p}} ==ဗွဟ်ရမ္သာၚ်== *{{IPAchar|/-/}} ==ကာရန်ဂမၠိုၚ်=="
399923
wikitext
text/x-wiki
{{rhymes nav|pl|u|p}}
==ဗွဟ်ရမ္သာၚ်==
*{{IPAchar|/-/}}
==ကာရန်ဂမၠိုၚ်==
3o7fxf9zydlfmo7ulpjyjzf1ycz8hum
ကဏ္ဍ:ကာရန်:ကသှုဗဳယာန်/op
14
297603
399924
2026-07-23T05:56:29Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » :..."
399924
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » [[:ကဏ္ဍ:ကာရန်:ကသှုဗဳယာန်|ကာရန်ဂမၠိုၚ်]] » -op
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]]မနွံကာရန် op ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ကသှုဗဳယာန်|op]]
hhkd34z9dpo3t1l8ywkp5s6qgs5al2y
ကဏ္ဍ:နာမ်ပုလ္လိၚ်ပဝ်လာန်တြေံဂမၠိုၚ်
14
297604
399925
2026-07-23T06:00:08Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ|ပဝ်လာန်တြေံ]]..."
399925
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ|ပဝ်လာန်တြေံ]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကပဝ်လာန်တြေံဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] » [[:ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ဗက်အလိုက်လိၚ်ဂမၠိုၚ်]] »'''ပုလ္လိၚ်ဂမၠိုၚ်'''
:နာမ်ပဝ်လာန်တြေံမဆေၚ်စပ်ကဵုလိၚ်တြုံ၊ ဥပမာ ဆေၚ်စပ်ကဵုကဏ္ဍလုပ်အဝေါၚ်လိၚ်အတေံ (အကြာတၞဟ်ခြာအရာမွဲမွဲအဂှ်) မက္တဵုဒှ်ပုလ္လိၚ်ဂမၠိုၚ်။
[[ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ပ]][[ကဏ္ဍ:နာမ်ပုလ္လိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]
f73xdc33cf8cojelkfjr44z02s63clk
ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဗက်အလိုက်လိၚ်ဂမၠိုၚ်
14
297605
399926
2026-07-23T06:01:43Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ|ပဝ်လာန်တြေံ]]..."
399926
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ|ပဝ်လာန်တြေံ]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကပဝ်လာန်တြေံဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] »'''ဗက်အလိုက်လိၚ်ဂမၠိုၚ်'''
:နာမ်ပဝ်လာန်တြေံမဂကောံလဝ်နူကဵုဆေၚ်စပ်ကဵုလိၚ်ပွမတုဲဒှ်နကဵုအတေံ။
[[ကဏ္ဍ:နာမ်ပဝ်လာန်တြေံဂမၠိုၚ်]][[ကဏ္ဍ:နာမ်နူကဵုလိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ပ]]
33e3fp8qssutvqvq23w52mhontgleem
ကဏ္ဍ:နာမ်မသက္ကုဟၟဲကဵုလမျီုနကဵုဘာသာပဝ်လာန်တြေံဂမၠိုၚ်
14
297606
399927
2026-07-23T06:04:36Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ]]"
399927
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာပဝ်လာန်တြေံ]]
5n0r6e567l9dnk64xu3feq0uvmlgqf3
ကဏ္ဍ:နာမ်ပုလ္လိၚ်ကသှုဗဳယာန်ဂမၠိုၚ်
14
297607
399928
2026-07-23T06:08:36Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » :..."
399928
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကကသှုဗဳယာန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်ကသှုဗဳယာန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] » [[:ကဏ္ဍ:နာမ်ကသှုဗဳယာန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ဗက်အလိုက်လိၚ်ဂမၠိုၚ်]] »'''ပုလ္လိၚ်ဂမၠိုၚ်'''
:နာမ်ကသှုဗဳယာန်မဆေၚ်စပ်ကဵုလိၚ်တြုံ၊ ဥပမာ ဆေၚ်စပ်ကဵုကဏ္ဍလုပ်အဝေါၚ်လိၚ်အတေံ (အကြာတၞဟ်ခြာအရာမွဲမွဲအဂှ်) မက္တဵုဒှ်ပုလ္လိၚ်ဂမၠိုၚ်။
[[ကဏ္ဍ:နာမ်ကသှုဗဳယာန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ပ]][[ကဏ္ဍ:နာမ်ပုလ္လိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|က]]
0j9wxu8ohhitgs7wcsq3v9hdow0fm3a
ကဏ္ဍ:နာမ်မသက္ကုဟၟဲကဵုလမျီုနကဵုဘာသာကသှုဗဳယာန်ဂမၠိုၚ်
14
297608
399929
2026-07-23T06:10:20Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]]"
399929
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]]
lfcv4195jmd1hdk59t8g4870pgo30s5
ကဏ္ဍ:နာမ်အဇ္ဇျတ္တိကာကသှုဗဳယာန်ဂမၠိုၚ်
14
297609
399930
2026-07-23T06:11:29Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]]"
399930
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]]
lfcv4195jmd1hdk59t8g4870pgo30s5
żłóbk
0
297610
399934
2026-07-23T06:54:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ကသှုဗဳယာန်== ===နာမ်=== {{head|csb|ဗီုပြၚ်နာမ်}} # {{plural of|csb|żłób}}"
399934
wikitext
text/x-wiki
==ကသှုဗဳယာန်==
===နာမ်===
{{head|csb|ဗီုပြၚ်နာမ်}}
# {{plural of|csb|żłób}}
t15ugdnm3j5ri1txoosg9x2cmbw511l
ကဏ္ဍ:ဗီုပြၚ်နာမ်ကသှုဗဳယာန်ဂမၠိုၚ်
14
297611
399935
2026-07-23T07:05:44Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » :..."
399935
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » [[:ကဏ္ဍ:ဗီုပြၚ်အပြံၚ်အလှာဲကသှုဗဳယာန်မၠိုၚ်|ဗီုပြၚ်ဝေါဟာတံသ္ဇိုၚ်]] » '''ဗီုပြၚ်နာမ်ဂမၠိုၚ်'''
:နာမ်ဂျာမာန်မပြံၚ်လှာဲနကဵုအဆက်အဆေန်မဆေၚ်စပ်ကဵုမဓမံက်ထ္ၜးသဒ္ဒာဗီုပြၚ်အဓိကတၞဟ်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]][[ကဏ္ဍ:နာမ်ကသှုဗဳယာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ဗီုပြၚ်နာမ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|က]]
lps5xby66fktf1qus9tp3k50medu6vq
ကဏ္ဍ:ဗီုပြၚ်အပြံၚ်အလှာဲကသှုဗဳယာန်ဂမၠိုၚ်
14
297612
399936
2026-07-23T07:07:18Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » '''..."
399936
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာကသှုဗဳယာန်|ကသှုဗဳယာန်]] » '''ဗီုပြၚ်ဝေါဟာတံသ္ဇိုၚ်ဂမၠိုၚ်'''
:ဗီုပြၚ်အပြံၚ်လှာဲဝေါဟာတံသ္ဇိုၚ်နဲတၞဟ်နကဵုဘာသာကသှုဗဳယာန်၊ ကဏ္ဍနူကဵုမပါ်ပရံဒကုတ်မဆေၚ်စပ်ကဵုမအရေဝ်ဝေါဟာ။
[[ကဏ္ဍ:ဘာသာကသှုဗဳယာန်]][[ကဏ္ဍ:ဗီုပြၚ်အပြံၚ်အလှာဲဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|က]]
02bcpb9svfruks2gxbr4atwanfckidt
żłobiszcze
0
297613
399937
2026-07-23T07:08:58Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ကသှုဗဳယာန်== ===နာမ်=== {{head|csb|ဗီုပြၚ်နာမ်}} # {{plural of|csb|żłób}}"
399937
wikitext
text/x-wiki
==ကသှုဗဳယာန်==
===နာမ်===
{{head|csb|ဗီုပြၚ်နာမ်}}
# {{plural of|csb|żłób}}
t15ugdnm3j5ri1txoosg9x2cmbw511l
żłobek
0
297614
399938
2026-07-23T07:12:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|Żłobek|żłóbek|Żłóbek}} ==ပဝ်လာန်== ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr|a=LL-Q809 (pol)-Olaf-żłobek.wav;LL-Q809 (pol)-Nostrix-żłobek.wav|hh=Żłobek}} ===နာမ်=== {{pl-noun|m-in}} # {{dim of|pl|żłób}} ====လဟုတ်စှ်ေ==== {{pl-decl-noun-m-in}}"
399938
wikitext
text/x-wiki
{{also|Żłobek|żłóbek|Żłóbek}}
==ပဝ်လာန်==
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr|a=LL-Q809 (pol)-Olaf-żłobek.wav;LL-Q809 (pol)-Nostrix-żłobek.wav|hh=Żłobek}}
===နာမ်===
{{pl-noun|m-in}}
# {{dim of|pl|żłób}}
====လဟုတ်စှ်ေ====
{{pl-decl-noun-m-in}}
bb64t3r851yarvcuxgf72d9s9puh59q
ကဏ္ဍ:ကာရန်:ပဝ်လာန်/ɔbɛk
14
297615
399939
2026-07-23T07:15:10Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » :ကဏ္ဍ:ကာ..."
399939
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -ɔbɛk
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် ɔbɛk ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ɔbɛk]]
7fy5ap50hr3jc65ven422kiy1t5sijn
żłóbek
0
297616
399940
2026-07-23T07:17:06Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|żłobek|Żłobek|Żłóbek}} ==ပဝ်လာန်== ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr|a=LL-Q809 (pol)-Nostrix-żłóbek.wav|hh=Żłóbek}} ===နာမ်=== {{pl-noun|m-in}} # {{dim of|pl|żłób}} ====လဟုတ်စှ်ေ==== {{pl-decl-noun-m-in}}"
399940
wikitext
text/x-wiki
{{also|żłobek|Żłobek|Żłóbek}}
==ပဝ်လာန်==
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr|a=LL-Q809 (pol)-Nostrix-żłóbek.wav|hh=Żłóbek}}
===နာမ်===
{{pl-noun|m-in}}
# {{dim of|pl|żłób}}
====လဟုတ်စှ်ေ====
{{pl-decl-noun-m-in}}
tqk8ul2t1qwix18rzvlpg055dnyre74
Żłobek
0
297617
399941
2026-07-23T07:17:42Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်လာန်== ===နာမ်=== {{pl-noun|m-in}} # {{dim of|pl|żłób}}"
399941
wikitext
text/x-wiki
==ပဝ်လာန်==
===နာမ်===
{{pl-noun|m-in}}
# {{dim of|pl|żłób}}
h6mw2b5m4vt12kvfbibkbz6yl5z3r8e
Żłóbek
0
297618
399942
2026-07-23T07:17:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်လာန်== ===နာမ်=== {{pl-noun|m-in}} # {{dim of|pl|żłób}}"
399942
wikitext
text/x-wiki
==ပဝ်လာန်==
===နာမ်===
{{pl-noun|m-in}}
# {{dim of|pl|żłób}}
h6mw2b5m4vt12kvfbibkbz6yl5z3r8e
żłobić
0
297619
399943
2026-07-23T07:43:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်လာန်== {{was wotd|၂၀၂၆|ဂျူလာင်|၂၄}} ===နိရုတ်=== {{inh+|pl|sla-pro|*želbiti}} ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr|a=LL-Q809 (pol)-Nostrix-żłobić.wav}} ===ကြိယာ=== {{pl-verb|impf}} # သကဵုကရောၚ်။ # သကဵုကွဵုပ္တိတ်။ # သကဵုပြဘိုက်ဇမ္ၚောဲ။ ====သ..."
399943
wikitext
text/x-wiki
==ပဝ်လာန်==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၄}}
===နိရုတ်===
{{inh+|pl|sla-pro|*želbiti}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr|a=LL-Q809 (pol)-Nostrix-żłobić.wav}}
===ကြိယာ===
{{pl-verb|impf}}
# သကဵုကရောၚ်။
# သကဵုကွဵုပ္တိတ်။
# သကဵုပြဘိုက်ဇမ္ၚောဲ။
====သမ္ဗန္ဓ====
{{pl-conj-ai-ić|żło|b|pp|imp=żłób}}
9bhle2cgmb968tufjcmhjmgon6mi4z5
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၄
4
297620
399944
2026-07-23T07:45:11Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|żłobić|ကြိယာ| သကဵုကရောၚ်။ # သကဵုကွဵုပ္တိတ်။ # သကဵုပြဘိုက်ဇမ္ၚောဲ။|audio=LL-Q809 (pol)-Nostrix-żłobić.wav|ဂျူလာင်|၂၄}}"
399944
wikitext
text/x-wiki
{{WOTD|żłobić|ကြိယာ| သကဵုကရောၚ်။
# သကဵုကွဵုပ္တိတ်။
# သကဵုပြဘိုက်ဇမ္ၚောဲ။|audio=LL-Q809 (pol)-Nostrix-żłobić.wav|ဂျူလာင်|၂၄}}
plpw48x6u8moyg4xs1y111y38lgyutx
ထာမ်ပလိက်:pl-conj-ai-ić
10
297621
399945
2026-07-23T07:46:42Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{pl-conj-ai|{{{1}}}{{{2}}}ić|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}ę|{{{1}}}{{{2}}}i|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}ą|{{{1}}}{{{2}}}i|{{{1}}}{{{2}}}i|{{{1}}}{{{2}}}i|{{#if:{{{imp|}}}|{{{imp}}}|{{{1}}}{{#switch:{{{2}}}|=j|c=ć|dz=dź|l=l|n=ń|s=ś|z=ź|śc=ść|źdz=źdź|{{{2}}}}}}}|ip={{{1}}}{{#switch:{{{2}}}|=j|c|dz|..."
399945
wikitext
text/x-wiki
{{pl-conj-ai|{{{1}}}{{{2}}}ić|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}ę|{{{1}}}{{{2}}}i|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}ą|{{{1}}}{{{2}}}i|{{{1}}}{{{2}}}i|{{{1}}}{{{2}}}i|{{#if:{{{imp|}}}|{{{imp}}}|{{{1}}}{{#switch:{{{2}}}|=j|c=ć|dz=dź|l=l|n=ń|s=ś|z=ź|śc=ść|źdz=źdź|{{{2}}}}}}}|ip={{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}ono|vn={{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}enie|pp={{#ifeq:{{{3}}}|pp|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}on}}|pp2={{#ifeq:{{{3}}}|pp|{{{1}}}{{#switch:{{{2}}}|=j|c|dz|l={{{2}}}|s=sz|z=ż|śc=szcz|źdz=żdż|{{{2}}}i}}eni}}}}<noinclude>{{documentation}}</noinclude>
36i6vmhjmnsxc7p1kp9p8vjtcfe03pv
ထာမ်ပလိက်:pl-conj-ai-ić/documentation
10
297622
399946
2026-07-23T07:58:23Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} ==Purpose== Shortcut for [[Template:pl-conj-ai]] for a frequent conjugation class of '''imperfective''' verbs. Displays infinitive, present tense, past tense, future tense, conditional, imperative, active adjectival participle, passive adjectival participle (if applicable and requested), impersonal past and verbal noun. If any of these forms does not exist or is in some way irregular then thi..."
399946
wikitext
text/x-wiki
{{documentation subpage}}
==Purpose==
Shortcut for [[Template:pl-conj-ai]] for a frequent conjugation class of '''imperfective''' verbs. Displays infinitive, present tense, past tense, future tense, conditional, imperative, active adjectival participle, passive adjectival participle (if applicable and requested), impersonal past and verbal noun. If any of these forms does not exist or is in some way irregular then this template cannot be used.
==Usage==
<tt><nowiki>====Conjugation====</nowiki></tt><br>
<tt><nowiki>{{pl-conj-ai-ić||}}</nowiki></tt>
Two mandatory parameters: (1) infinitive minus the final consonant or cluster (2) the final consonant or cluster.
If <code>pp</code> is specified as the third parameter then the passive adjectival participle is included in the conjugation table.
==Example==
* [[bawić]]: {{temp|pl-conj-ai-ić|ba|w|pp}}
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်|conj-ai-ić]]
</includeonly>
2ktw5xzzy1evytch36a5n4wgxaljljo
ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်
14
297623
399947
2026-07-23T07:59:02Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|က]]"
399947
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|က]]
3useizgf9zcukly0mumj3ncfohnk5sk
ထာမ်ပလိက်:pl-conj-ai
10
297624
399948
2026-07-23T08:32:45Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|error}}<!-- Validate template parameters -->{{inflection-table-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|pl||{{{1}}}|g=impf}}|category=conjugation|tall=yes|palette=blue|class=wide}} ! rowspan="2" | ! rowspan="2" title="osoba" | ပူဂဵု ! colspan="3" title="liczba pojedyncza" | ကိုန်ဨကဝုစ် ! colspan="2" title="liczba mnoga" | ကိုန်ဗ..."
399948
wikitext
text/x-wiki
{{#invoke:checkparams|error}}<!-- Validate template parameters
-->{{inflection-table-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|pl||{{{1}}}|g=impf}}|category=conjugation|tall=yes|palette=blue|class=wide}}
! rowspan="2" |
! rowspan="2" title="osoba" | ပူဂဵု
! colspan="3" title="liczba pojedyncza" | ကိုန်ဨကဝုစ်
! colspan="2" title="liczba mnoga" | ကိုန်ဗဟုဝစ်
|- class="ts-pl-conj-header vsHide"
! class="secondary" title="rodzaj męski" | ပုလ္လိၚ်
! class="secondary" title="rodzaj żeński" | ဣတ္တိလိၚ်
! class="secondary" title="rodzaj nijaki" | နပုလ္လိၚ်
! class="secondary" title="rodzaj męskoosobowy" | ပရေၚ်မထတ်
! class="secondary" title="rodzaj niemęskoosobowy" | မသက္ကုဟွံသေၚ်
|-
! colspan="2" title="bezokolicznik" | ဟွံချိုတ်ပၠိုတ်
| colspan="5" | {{{inf|{{{1}}}}}}
|-
! rowspan="4" title="czas teraźniejszy" | ကာလပစ္စုပ္ပန်
! class="secondary" title="pierwsza osoba (ja, my)" | မရနုက်ကဵု<sup>၁</sup>
| colspan="3" | {{l|pl|{{{pr1s|{{{2}}}}}}|accel-form=1{{!}}s{{!}}pres}}
| colspan="2" | {{l|pl|{{{pr1p|{{{3}}}my}}}|accel-form=1{{!}}p{{!}}pres}}
|-
! class="secondary" title="druga osoba (ty, wy)" | မရနုက်ကဵု<sup>၂</sup>
| colspan="3" | {{l|pl|{{{pr2s|{{{3}}}sz}}}|accel-form=2{{!}}s{{!}}pres}}
| colspan="2" | {{l|pl|{{{pr2p|{{{3}}}cie}}}|accel-form=2{{!}}p{{!}}pres}}
|-
! class="secondary" title="trzecia osoba (on, ona, ono, pan, pani, oni, one, państwo)" | မရနုက်ကဵု<sup>၃</sup>
| colspan="3" | {{l|pl|{{{pr3s|{{{3}}}}}}|accel-form=3{{!}}s{{!}}pres}}
| colspan="2" | {{l|pl|{{{pr3p|{{{4}}}}}}|accel-form=3{{!}}p{{!}}pres}}
|-
! class="secondary" title="forma bezosobowa" | ပါဲဗလေတ်ဟွံဗၠး
| colspan="5" | {{l|pl|[[{{{primpers|{{{3}}}}}}]] [[się]]}}
|-
! rowspan="{{#if: {{{ip|}}} | 4 | 3 }}" title="czas przeszły" | past tense
! class="secondary" title="pierwsza osoba (ja, my)" | မရနုက်ကဵု<sup>၁</sup>
| {{l|pl|{{{pa1sm|{{{5}}}łem}}}|accel-form=1{{!}}s{{!}}m{{!}}past}},<br> {{l|pl|[[-m|-(e)m]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}}
| {{l|pl|{{{pa1sf|{{{6}}}łam}}}|accel-form=1{{!}}s{{!}}f{{!}}past}},<br> {{l|pl|[[-m|-(e)m]] [[{{{6}}}ła]]}}
| {{l|pl|{{{pa1sn|{{{6}}}łom}}}|accel-form=1{{!}}s{{!}}n{{!}}past}},<br> {{l|pl|[[-m|-(e)m]] [[{{{6}}}ło]]}}
| {{l|pl|{{{pa1pmpr|{{{7}}}liśmy}}}|accel-form=1{{!}}p{{!}}vr{{!}}past}},<br> {{l|pl|[[-śmy|-(e)śmy]] [[{{{7}}}li]]}}
| {{l|pl|{{{pa1poth|{{{6}}}łyśmy}}}|accel-form=1{{!}}p{{!}}nv{{!}}past}},<br> {{l|pl|[[-śmy|-(e)śmy]] [[{{{6}}}ły]]}}
|-
! class="secondary" title="druga osoba (ty, wy)" | မရနုက်ကဵု<sup>၂</sup>
| {{l|pl|{{{pa2sm|{{{5}}}łeś}}}|accel-form=2{{!}}s{{!}}m{{!}}past}},<br> {{l|pl|[[-ś|-(e)ś]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}}
| {{l|pl|{{{pa2sf|{{{6}}}łaś}}}|accel-form=2{{!}}s{{!}}f{{!}}past}},<br> {{l|pl|[[-ś|-(e)ś]] [[{{{6}}}ła]]}}
| {{l|pl|{{{pa2sn|{{{6}}}łoś}}}|accel-form=2{{!}}s{{!}}n{{!}}past}},<br> {{l|pl|[[-ś|-(e)ś]] [[{{{6}}}ło]]}}
| {{l|pl|{{{pa2pmpr|{{{7}}}liście}}}|accel-form=2{{!}}p{{!}}vr{{!}}past}},<br> {{l|pl|[[-ście|-(e)ście]] [[{{{7}}}li]]}}
| {{l|pl|{{{pa2poth|{{{6}}}łyście}}}|accel-form=2{{!}}p{{!}}nv{{!}}past}},<br> {{l|pl|[[-ście|-(e)ście]] [[{{{6}}}ły]]}}
|-
! class="secondary" title="trzecia osoba (on, ona, ono, pan, pani, oni, one, państwo)" | မရနုက်ကဵု<sup>၃</sup>
| {{l|pl|{{{pa3sm|{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł}}}|accel-form=3{{!}}s{{!}}m{{!}}past}}
| {{l|pl|{{{pa3sf|{{{6}}}ła}}}|accel-form=3{{!}}s{{!}}f{{!}}past}}
| {{l|pl|{{{pa3sn|{{{6}}}ło}}}|accel-form=3{{!}}s{{!}}n{{!}}past}}
| {{l|pl|{{{pa3pmpr|{{{7}}}li}}}|accel-form=3{{!}}p{{!}}vr{{!}}past}}
| {{l|pl|{{{pa3poth|{{{6}}}ły}}}|accel-form=3{{!}}p{{!}}nv{{!}}past}}
{{#if: {{{ip|}}} |
{{!-}}
! class="secondary" title="forma bezosobowa" {{!}} ပါဲဗလေတ်ဟွံဗၠး
{{!}} colspan="5" {{!}} {{l|pl|{{{ip}}}|accel-form=impers{{!}}past}}
}}
|-
! rowspan="4" title="czas przyszły" | future tense
! class="secondary" title="pierwsza osoba (ja, my)" | မရနုက်ကဵု<sup>၁</sup>
| {{l|pl|[[będę]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}},<br>będę {{{1}}}
| {{l|pl|[[będę]] [[{{{6}}}ła]]}},<br>będę {{{1}}}
| {{l|pl|[[będę]] [[{{{6}}}ło]]}},<br>będę {{{1}}}
| {{l|pl|[[będziemy]] [[{{{7}}}li]]}},<br>będziemy {{{1}}}
| {{l|pl|[[będziemy]] [[{{{6}}}ły]]}},<br>będziemy {{{1}}}
|-
! class="secondary" title="druga osoba (ty, wy)" | မရနုက်ကဵု<sup>၂</sup>
| {{l|pl|[[będziesz]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}},<br>będziesz {{{1}}}
| {{l|pl|[[będziesz]] [[{{{6}}}ła]]}},<br>będziesz {{{1}}}
| {{l|pl|[[będziesz]] [[{{{6}}}ło]]}},<br>będziesz {{{1}}}
| {{l|pl|[[będziecie]] [[{{{7}}}li]]}},<br>będziecie {{{1}}}
| {{l|pl|[[będziecie]] [[{{{6}}}ły]]}},<br>będziecie {{{1}}}
|-
! class="secondary" title="trzecia osoba (on, ona, ono, pan, pani, oni, one, państwo)" | မရနုက်ကဵု<sup>၃</sup>
| {{l|pl|[[będzie]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}},<br>będzie {{{1}}}
| {{l|pl|[[będzie]] [[{{{6}}}ła]]}},<br>będzie {{{1}}}
| {{l|pl|[[będzie]] [[{{{6}}}ło]]}},<br>będzie {{{1}}}
| {{l|pl|[[będą]] [[{{{7}}}li]]}},<br>będą {{{1}}}
| {{l|pl|[[będą]] [[{{{6}}}ły]]}},<br>będą {{{1}}}
|-
! class="secondary" title="forma bezosobowa" | ပါဲဗလေတ်ဟွံဗၠး
| colspan="5" | {{l|pl|[[będzie]] {{{1}}} [[się]]}}
|-
! rowspan="{{#if: {{{ip|}}} | 4 | 3 }}" title="tryb przypuszczający" | တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်
! class="secondary" title="pierwsza osoba (ja, my)" | မရနုက်ကဵု<sup>၁</sup>
| {{l|pl|{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}łbym|accel-form=1{{!}}s{{!}}m{{!}}cond}},<br> {{l|pl|[[bym]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}}
| {{l|pl|{{{6}}}łabym|accel-form=1{{!}}s{{!}}f{{!}}cond}},<br> {{l|pl|[[bym]] [[{{{6}}}ła]]}}
| {{l|pl|{{{6}}}łobym|accel-form=1{{!}}s{{!}}n{{!}}cond}},<br> {{l|pl|[[bym]] [[{{{6}}}ło]]}}
| {{l|pl|{{{7}}}libyśmy|accel-form=1{{!}}p{{!}}vr{{!}}cond}},<br> {{l|pl|[[byśmy]] [[{{{7}}}li]]}}
| {{l|pl|{{{6}}}łybyśmy|accel-form=1{{!}}p{{!}}nv{{!}}cond}},<br> {{l|pl|[[byśmy]] [[{{{6}}}ły]]}}
|-
! class="secondary" title="druga osoba (ty, wy)" | မရနုက်ကဵု<sup>၂</sup>
| {{l|pl|{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}łbyś|accel-form=2{{!}}s{{!}}m{{!}}cond}},<br> {{l|pl|[[byś]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}}
| {{l|pl|{{{6}}}łabyś|accel-form=2{{!}}s{{!}}f{{!}}cond}},<br> {{l|pl|[[byś]] [[{{{6}}}ła]]}}
| {{l|pl|{{{6}}}łobyś|accel-form=2{{!}}s{{!}}n{{!}}cond}},<br> {{l|pl|[[byś]] [[{{{6}}}ło]]}}
| {{l|pl|{{{7}}}libyście|accel-form=2{{!}}p{{!}}vr{{!}}cond}},<br> {{l|pl|[[byście]] [[{{{7}}}li]]}}
| {{l|pl|{{{6}}}łybyście|accel-form=2{{!}}p{{!}}nv{{!}}cond}},<br> {{l|pl|[[byście]] [[{{{6}}}ły]]}}
|-
! class="secondary" title="trzecia osoba (on, ona, ono, pan, pani, oni, one, państwo)" | မရနုက်ကဵု<sup>၃</sup>
| {{l|pl|{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}łby|accel-form=3{{!}}s{{!}}m{{!}}cond}},<br> {{l|pl|[[by]] [[{{#if: {{{altpasttense|}}} | {{{altpasttense}}} | {{{5}}} }}ł]]}}
| {{l|pl|{{{6}}}łaby|accel-form=3{{!}}s{{!}}f{{!}}cond}},<br> {{l|pl|[[by]] [[{{{6}}}ła]]}}
| {{l|pl|{{{6}}}łoby|accel-form=3{{!}}s{{!}}n{{!}}cond}},<br> {{l|pl|[[by]] [[{{{6}}}ło]]}}
| {{l|pl|{{{7}}}liby|accel-form=3{{!}}p{{!}}vr{{!}}cond}},<br> {{l|pl|[[by]] [[{{{7}}}li]]}}
| {{l|pl|{{{6}}}łyby|accel-form=3{{!}}p{{!}}nv{{!}}cond}},<br> {{l|pl|[[by]] [[{{{6}}}ły]]}}
{{#if: {{{ip|}}} |
{{!-}}
! class="secondary" title="forma bezosobowa" {{!}} တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်
{{!}} colspan="5" {{!}} {{l|pl|[[{{{ip}}}]] [[by]]}}
}}
|-
! rowspan="3" title="tryb rozkazujący" | ပါဲဗလေတ်ဟွံဗၠး
! class="secondary" title="pierwsza osoba (ja, my)" | မရနုက်ကဵု<sup>၁</sup>
| colspan="3" | {{#if: {{{noimp|}}} | — | {{l|pl|[[niech]] [[{{{2}}}]]}} }}
| colspan="2" | {{#if: {{{noimp|}}} | — | {{l|pl|{{{8}}}my|accel-form=1{{!}}p{{!}}impr}} }}
|-
! class="secondary" title="druga osoba (ty, wy)" | မရနုက်ကဵု<sup>၂</sup>
| colspan="3" | {{#if: {{{altimperative|}}} | {{{altimperative}}} | {{l|pl|{{{8}}}|accel-form=2{{!}}s{{!}}impr}} }}
| colspan="2" | {{#if: {{{noimp|}}} | — | {{l|pl|{{{8}}}cie|accel-form=2{{!}}p{{!}}impr}} }}
|-
! class="secondary" title="trzecia osoba (on, ona, ono, pan, pani, oni, one, państwo)" | မရနုက်ကဵု<sup>၃</sup>
| colspan="3" | {{#if: {{{noimp|}}} | — | {{l|pl|[[niech]] [[{{{3}}}]]}} }}
| colspan="2" | {{#if: {{{noimp|}}} | — | {{l|pl|[[niech]] [[{{{4}}}]]}} }}
|-
| class="separator" colspan=999 |
|-
! colspan="2" title="imiesłów przymiotnikowy czynny" | လုပ်ကၠောန်စွံလဝ်ဆေၚ်စပ်ကဵုနာမဝိသေသနမစိုပ်တရဴ
| {{l|pl|{{{4}}}cy|accel-form=active adjectival participle}}
| {{l|pl|{{{4}}}ca|accel-lemma={{{4}}}cy|accel-form=s{{!}}f{{!}}active adjectival participle}}
| {{l|pl|{{{4}}}ce|accel-lemma={{{4}}}cy|accel-form=s{{!}}n{{!}}active adjectival participle}}
| {{l|pl|{{{4}}}cy|accel-lemma={{{4}}}cy|accel-form=p{{!}}vr{{!}}active adjectival participle}}
| {{l|pl|{{{4}}}ce|accel-lemma={{{4}}}cy|accel-form=p{{!}}nv{{!}}active adjectival participle}}
{{#if: {{{pp<includeonly>|</includeonly>}}} |
{{!-}}
! colspan="2" title="imiesłów przymiotnikowy bierny" {{!}} လုပ်ကၠောန်စွံလဝ်ဆေၚ်စပ်ကဵုနာမဝိသေသနပရေၚ်ဒုၚ်ကေတ်
{{!}} {{l|pl|{{{pp}}}y|accel-form=passive adjectival participle}}{{#if: {{{pp3|}}} | <br>({{{pp3}}}y) }}
{{!}} {{l|pl|{{{pp}}}a|accel-lemma={{{pp}}}y|accel-form=s{{!}}f{{!}}passive adjectival participle}}{{#if: {{{pp3|}}} | <br>({{{pp3}}}a) }}
{{!}} {{l|pl|{{{pp}}}e|accel-lemma={{{pp}}}y|accel-form=s{{!}}n{{!}}passive adjectival participle}}{{#if: {{{pp3|}}} | <br>({{{pp3}}}e) }}
{{!}} {{l|pl|{{{pp2|}}}|accel-lemma={{{pp}}}y|accel-form=p{{!}}vr{{!}}passive adjectival participle}}{{#if: {{{pp4|}}} | <br>({{{pp4}}}) }}
{{!}} {{l|pl|{{{pp}}}e|accel-lemma={{{pp}}}y|accel-form=p{{!}}nv{{!}}passive adjectival participle}}{{#if: {{{pp3|}}} | <br>({{{pp3}}}e) }}
}}
|-
! colspan="2" title="imiesłów przysłówkowy współczesny" | လုပ်ကၠောန်စွံလဝ်ဆေၚ်စပ်ကဵုကြိယာဝိသေသနမွဲအခိၚ်ဓဝ်
| colspan="5" | {{l|pl|{{{4}}}c|accel-form=contemporary adverbial participle}}
{{#if: {{{vn<includeonly>|</includeonly>}}} |
{{!-}}
! colspan="2" title="rzeczownik odczasownikowy" {{!}} နာမ်ပါၚ်တိုက်
{{!}} colspan="5" {{!}} {{l|pl|{{{vn}}}|accel-form=verbal noun}}
}}
{{inflection-table-bottom}}<noinclude>{{documentation}}</noinclude>
3e5qmssqoly1376vkqrucvg8tyesdt6
ထာမ်ပလိက်:pl-conj-ai/documentation
10
297625
399949
2026-07-23T08:34:39Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} This is a comprehensive conjugation table for Polish verbs of '''''i'''mperfective '''a'''spect''. Should display correctly present tense, past tense, future tense, imperative, active adjectival and present adverbial participles for all but the most irregular verbs. Other forms (impersonal past, passive participle, verbal noun) are shown if applicable and if they have been provided in the ca..."
399949
wikitext
text/x-wiki
{{documentation subpage}}
This is a comprehensive conjugation table for Polish verbs of '''''i'''mperfective '''a'''spect''.
Should display correctly present tense, past tense, future tense, imperative, active adjectival and present adverbial participles for all but the most irregular verbs. Other forms (impersonal past, passive participle, verbal noun) are shown if applicable and if they have been provided in the call of the template.
===Usage===
<syntaxhighlight lang="wikitext">
====Conjugation====
{{pl-conj-ai|||||||||
pp=|pp2=|ip=|vn=|altpasttense=}}
</syntaxhighlight>
Eight mandatory arguments, with examples in bold:
# infinitive: '''robić''', '''wieźć'''
# first person singular present tense: '''robię''', '''wiozę'''
# third person singular present tense: '''robi''', '''wiezie'''
# third person plural present tense: '''robią''', '''wiozą'''
# third person singular past tense, masculine, without ł: '''robi'''ł, '''wióz'''ł [but enter '''wioz'''; see below]
# third person singular past tense, feminine, without ła: '''robi'''ła, '''wioz'''ła
# third person plural past tense, masculine, without li: '''robi'''li, '''wieź'''li
# second person singular imperative: '''rób''', '''wieź'''
Five optional arguments:
# <code>pp=</code> passive adjectival participle, without y (must be combined with pp2): '''robion'''y, '''wiezion'''y
# <code>pp2=</code> passive adjectival participle, masculine-personal plural: '''robieni''', '''wiezieni'''
# <code>ip=</code> impersonal past: '''robiono''', '''wieziono'''
# <code>vn=</code> verbal noun: '''robienie''', '''wiezienie'''
# <code>altpasttense=</code> third-person masculine singular past form without ł: '''robi'''[ł], '''wióz'''[ł] (cf. '''wioz'''łem/-eś, which you'd enter as the main masculine past form instead)
Shortcuts for frequent conjugations:
* {{temp|pl-conj-ai-am,asz}}
* {{temp|pl-conj-ai-uję}}
===See also===
* {{temp|pl-conj-ap}} – for verbs of perfective aspect
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်]]
</includeonly>
mq1w74akbzhzccxfq8jn398kl7hfg0k
399950
399949
2026-07-23T08:35:43Z
咽頭べさ
33
399950
wikitext
text/x-wiki
{{documentation subpage}}
This is a comprehensive conjugation table for Polish verbs of '''''i'''mperfective '''a'''spect''.
Should display correctly present tense, past tense, future tense, imperative, active adjectival and present adverbial participles for all but the most irregular verbs. Other forms (impersonal past, passive participle, verbal noun) are shown if applicable and if they have been provided in the call of the template.
===Usage===
<syntaxhighlight lang="wikitext">
====သမ္ဗန္ဓ====
{{pl-conj-ai|||||||||
pp=|pp2=|ip=|vn=|altpasttense=}}
</syntaxhighlight>
Eight mandatory arguments, with examples in bold:
# infinitive: '''robić''', '''wieźć'''
# first person singular present tense: '''robię''', '''wiozę'''
# third person singular present tense: '''robi''', '''wiezie'''
# third person plural present tense: '''robią''', '''wiozą'''
# third person singular past tense, masculine, without ł: '''robi'''ł, '''wióz'''ł [but enter '''wioz'''; see below]
# third person singular past tense, feminine, without ła: '''robi'''ła, '''wioz'''ła
# third person plural past tense, masculine, without li: '''robi'''li, '''wieź'''li
# second person singular imperative: '''rób''', '''wieź'''
Five optional arguments:
# <code>pp=</code> passive adjectival participle, without y (must be combined with pp2): '''robion'''y, '''wiezion'''y
# <code>pp2=</code> passive adjectival participle, masculine-personal plural: '''robieni''', '''wiezieni'''
# <code>ip=</code> impersonal past: '''robiono''', '''wieziono'''
# <code>vn=</code> verbal noun: '''robienie''', '''wiezienie'''
# <code>altpasttense=</code> third-person masculine singular past form without ł: '''robi'''[ł], '''wióz'''[ł] (cf. '''wioz'''łem/-eś, which you'd enter as the main masculine past form instead)
Shortcuts for frequent conjugations:
* {{temp|pl-conj-ai-am,asz}}
* {{temp|pl-conj-ai-uję}}
===See also===
* {{temp|pl-conj-ap}} – for verbs of perfective aspect
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်]]
</includeonly>
38oxf6yovwy838khmw2j5j7ycwgsj79
ဗီုပြၚ်သိုၚ်တၟိ:သလာဗေတ်-အခိုက်ကၞာ/želbiti
118
297626
399951
2026-07-23T08:51:16Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{reconstructed}} ==သလာဗေတ်-အခိုက်ကၞာ== ===ကြိယာ=== {{head|sla-pro|ကြိယာ}} # သကဵုကရောၚ်။"
399951
wikitext
text/x-wiki
{{reconstructed}}
==သလာဗေတ်-အခိုက်ကၞာ==
===ကြိယာ===
{{head|sla-pro|ကြိယာ}}
# သကဵုကရောၚ်။
hu0fewx6dw7hnvqrphu87nz0wbdszup
ကဏ္ဍ:ကာရန်:ပဝ်လာန်/ɔbit͡ɕ
14
297627
399952
2026-07-23T08:56:23Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » :ကဏ္ဍ:ကာ..."
399952
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -ɔbit͡ɕ
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် ɔbit͡ɕ ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ɔbit͡ɕ]]
2ld1ltatia0zbrwpjtwfmsc9l166alk
żłōb
0
297628
399953
2026-07-23T09:06:57Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zlob|żlób|żłōb|żłób}} ==သလဳယှေန်== ===ဗွဟ်ရမ္သာၚ်=== {{szl-pr}} ===နာမ်=== {{szl-noun|m-in|dim=żłobek}} # ဍာ်ကရံက်။"
399953
wikitext
text/x-wiki
{{also|zlob|żlób|żłōb|żłób}}
==သလဳယှေန်==
===ဗွဟ်ရမ္သာၚ်===
{{szl-pr}}
===နာမ်===
{{szl-noun|m-in|dim=żłobek}}
# ဍာ်ကရံက်။
leq59j0bx33hn51zkbxy7ol6ww0b91v
ကဏ္ဍ:နာမ်ပုလ္လိၚ်သလဳယှေန်ဂမၠိုၚ်
14
297629
399954
2026-07-23T09:15:03Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » :ကဏ္ဍ:..."
399954
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကသလဳယှေန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်သလဳယှေန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] » [[:ကဏ္ဍ:နာမ်သလဳယှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ဗက်အလိုက်လိၚ်ဂမၠိုၚ်]] »'''ပုလ္လိၚ်ဂမၠိုၚ်'''
:နာမ်သလဳယှေန်မဆေၚ်စပ်ကဵုလိၚ်တြုံ၊ ဥပမာ ဆေၚ်စပ်ကဵုကဏ္ဍလုပ်အဝေါၚ်လိၚ်အတေံ (အကြာတၞဟ်ခြာအရာမွဲမွဲအဂှ်) မက္တဵုဒှ်ပုလ္လိၚ်ဂမၠိုၚ်။
[[ကဏ္ဍ:နာမ်သလဳယှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ပ]][[ကဏ္ဍ:နာမ်ပုလ္လိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
etm7gaqlp1ylk34q8xhno2r0vz0u55k
ကဏ္ဍ:နာမ်သလဳယှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်
14
297630
399955
2026-07-23T09:18:34Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » :ကဏ္ဍ:..."
399955
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကသလဳယှေန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်သလဳယှေန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] »'''ဗက်အလိုက်လိၚ်ဂမၠိုၚ်'''
:နာမ်သလဳယှေန်မဂကောံလဝ်နူကဵုဆေၚ်စပ်ကဵုလိၚ်ပွမတုဲဒှ်နကဵုအတေံ။
[[ကဏ္ဍ:နာမ်သလဳယှေန်ဂမၠိုၚ်]][[ကဏ္ဍ:နာမ်နူကဵုလိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
b2bblpe814p64xoghj5e2qevzlvwql5
ကဏ္ဍ:နာမ်မသက္ကုဟၟဲကဵုလမျီုနကဵုဘာသာသလဳယှေန်ဂမၠိုၚ်
14
297631
399956
2026-07-23T09:20:49Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာသလဳယှေန်]]"
399956
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာသလဳယှေန်]]
q1urxidxvc6ccgggc97pe3j878erkhu
ကဏ္ဍ:ကာရန်:သလဳယှေန်/op
14
297632
399957
2026-07-23T09:28:44Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » :ကဏ္ဍ:..."
399957
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]] » [[:ကဏ္ဍ:ကာရန်:သလဳယှေန်|ကာရန်ဂမၠိုၚ်]] » -op
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာသလဳယှေန်|သလဳယှေန်]]မနွံကာရန် op ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:သလဳယှေန်|op]]
huo5fhrkbl0uefilxk5aikqzkq7sz58
żlób
0
297633
399958
2026-07-23T09:32:22Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zlob|żlób|żłōb|żłób}} ==သဋ္ဌဝ်ဗေန်ဃှေန်== ===ဗွဟ်ရမ္သာၚ်=== {{zlw-slv-pr}} ===နာမ်=== {{zlw-slv-noun|m-in|dim=żlóbk}} # ကရောၚ်။"
399958
wikitext
text/x-wiki
{{also|zlob|żlób|żłōb|żłób}}
==သဋ္ဌဝ်ဗေန်ဃှေန်==
===ဗွဟ်ရမ္သာၚ်===
{{zlw-slv-pr}}
===နာမ်===
{{zlw-slv-noun|m-in|dim=żlóbk}}
# ကရောၚ်။
gaonp2csv29n9o7c7yyqrtxcj12qtuk
ထာမ်ပလိက်:zlw-slv-noun
10
297634
399959
2026-07-23T09:33:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:zlw-lch-headword|show|နာမ်|lang=zlw-slv}}<!-- --><noinclude>{{documentation}}</noinclude>"
399959
wikitext
text/x-wiki
{{#invoke:zlw-lch-headword|show|နာမ်|lang=zlw-slv}}<!--
--><noinclude>{{documentation}}</noinclude>
25awoefm7xg16iemljyu8gt8uv6wj6e
ထာမ်ပလိက်:zlw-slv-noun/documentation
10
297635
399960
2026-07-23T09:34:38Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} This template is to be used in the headword lines for Slovincian common nouns. The parameters are like for {{tl|pl-noun}} (and other Lechitic noun templates), except that the headword should be specified (with appropriate accents) in {{para|1}} (with additional headwords in {{para|head2}}, {{para|head3}}, etc.), and the gender in {{para|2}}. See the documentation of {{tl|pl-noun}} for more in..."
399960
wikitext
text/x-wiki
{{documentation subpage}}
This template is to be used in the headword lines for Slovincian common nouns. The parameters are like for {{tl|pl-noun}} (and other Lechitic noun templates), except that the headword should be specified (with appropriate accents) in {{para|1}} (with additional headwords in {{para|head2}}, {{para|head3}}, etc.), and the gender in {{para|2}}. See the documentation of {{tl|pl-noun}} for more information.
{{hwcat}}
0ov4eny83cgk1u94x504f2nkdjfewrh
ကဏ္ဍ:နာမ်ပုလ္လိၚ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်
14
297636
399961
2026-07-23T09:37:56Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေ..."
399961
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကသဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] » [[:ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ဗက်အလိုက်လိၚ်ဂမၠိုၚ်]] »'''ပုလ္လိၚ်ဂမၠိုၚ်'''
:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်မဆေၚ်စပ်ကဵုလိၚ်တြုံ၊ ဥပမာ ဆေၚ်စပ်ကဵုကဏ္ဍလုပ်အဝေါၚ်လိၚ်အတေံ (အကြာတၞဟ်ခြာအရာမွဲမွဲအဂှ်) မက္တဵုဒှ်ပုလ္လိၚ်ဂမၠိုၚ်။
[[ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ပ]][[ကဏ္ဍ:နာမ်ပုလ္လိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
ta83yielhz6qgyvqo8xw0nr87nhvtzz
399962
399961
2026-07-23T09:39:21Z
咽頭べさ
33
399962
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကသဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] » [[:ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ဗက်အလိုက်လိၚ်ဂမၠိုၚ်]] »'''ပုလ္လိၚ်ဂမၠိုၚ်'''
:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်မဆေၚ်စပ်ကဵုလိၚ်တြုံ၊ ဥပမာ ဆေၚ်စပ်ကဵုကဏ္ဍလုပ်အဝေါၚ်လိၚ်အတေံ (အကြာတၞဟ်ခြာအရာမွဲမွဲအဂှ်) မက္တဵုဒှ်ပုလ္လိၚ်ဂမၠိုၚ်။
[[ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်|ပ]][[ကဏ္ဍ:နာမ်ပုလ္လိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
1cf41uwywf5stbxpagvcp050w4mmugv
ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဗက်အလိုက်လိၚ်ဂမၠိုၚ်
14
297637
399963
2026-07-23T09:40:21Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေ..."
399963
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]] » [[:ကဏ္ဍ:ဝေါဟာအဓိကသဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|ဝေါဟာတံသ္ဇိုၚ်]] » [[:ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်|နာမ်ဂမၠိုၚ်]] »'''ဗက်အလိုက်လိၚ်ဂမၠိုၚ်'''
:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်မဂကောံလဝ်နူကဵုဆေၚ်စပ်ကဵုလိၚ်ပွမတုဲဒှ်နကဵုအတေံ။
[[ကဏ္ဍ:နာမ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်]][[ကဏ္ဍ:နာမ်နူကဵုလိၚ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
r8jfz6vxmd0j66ggh1vwu6pachwer2m
ကဏ္ဍ:နာမ်မသက္ကုဟၟဲကဵုလမျီုနကဵုဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်
14
297638
399964
2026-07-23T09:41:47Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်]]"
399964
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်]]
511tsvgt9si3ocbih7du7ei3nfmyqe2
ကဏ္ဍ:ကာရန်:သဋ္ဌဝ်ဗေန်ဃှေန်/op
14
297639
399965
2026-07-23T09:43:49Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေ..."
399965
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]] » [[:ကဏ္ဍ:ကာရန်:သဋ္ဌဝ်ဗေန်ဃှေန်|ကာရန်ဂမၠိုၚ်]] » -op
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]]မနွံကာရန် op ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:သဋ္ဌဝ်ဗေန်ဃှေန်|op]]
p8xqxahydkb04d1e5nx85xzrnvo9eq2
ကဏ္ဍ:ကာရန်:သဋ္ဌဝ်ဗေန်ဃှေန်
14
297640
399966
2026-07-23T09:45:17Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်]][[ကဏ္ဍ:ကာရန်ဂမၠိုၚ်|သ]]"
399966
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်]][[ကဏ္ဍ:ကာရန်ဂမၠိုၚ်|သ]]
lps1kmy6taofo43tc7jbvzrf1nxol7l
ကဏ္ဍ:ဝေါဟာသဋ္ဌဝ်ဗေန်ဃှေန်ပ္တိတ်ရမျာၚ် IPA ဂမၠိုၚ်
14
297641
399967
2026-07-23T09:47:20Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » :ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေ..."
399967
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်|သဋ္ဌဝ်ဗေန်ဃှေန်]] » '''{{PAGENAME}}'''
:ဝေါဟာသဋ္ဌဝ်ဗေန်ဃှေန်လုပ်အဝေါၚ်မဆေၚ်စပ်မပ္တိတ်ရမျာၚ်ပ္ဍဲနကဵုဗီုပြၚ် IPA။
သွက်မအာတ်မိက်ဆေၚ်စပ်ကဵုကဏ္ဍတဏအ်၊ ဗဵုရံၚ် ကဏ္ဍ:မအာတ်မိက်သွက်ရမျာၚ်ပ္ဍဲစရၚ်သဋ္ဌဝ်ဗေန်ဃှေန်ဂမၠိုၚ်။
[[ကဏ္ဍ:ဘာသာသဋ္ဌဝ်ဗေန်ဃှေန်]][[ကဏ္ဍ:ဝေါဟာမနွံကဵုမပတိတ်ရမျာၚ် IPA ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|သ]]
58yg3e6kxvi9hb8kot6eda3diyna71u
zlob
0
297642
399968
2026-07-23T09:53:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zlob|żlób|żłōb|żłób}} ==ချက်ခ်== ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA}} ===ကြိယာ=== {{head|cs|verb form}} # {{infl of|cs|zlobit||2|s|impr}}"
399968
wikitext
text/x-wiki
{{also|zlob|żlób|żłōb|żłób}}
==ချက်ခ်==
===ဗွဟ်ရမ္သာၚ်===
* {{cs-IPA}}
===ကြိယာ===
{{head|cs|verb form}}
# {{infl of|cs|zlobit||2|s|impr}}
kv7jxddec2imloy9wr69y2ys9pmoup6
zlobit
0
297643
399969
2026-07-23T10:01:56Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ချက်ခ်== {{was wotd|၂၀၂၆|ဂျူလာင်|၂၅}} ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA}} * {{audio|cs|LL-Q9056 (ces)-Ghost4Man-{{pagename}}.wav}} ===ကြိယာ=== {{cs-verb|a=impf|pf=rozzlobit}} # သကဵုဂတာတ်၊ သကဵုလဳလှန်ဗ္ဂေတ်လ္ပာ်နာနာသာ်။ #: {{syn|cs|štvát|vadit}} # ပရေၚ်ဟီု..."
399969
wikitext
text/x-wiki
==ချက်ခ်==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၅}}
===ဗွဟ်ရမ္သာၚ်===
* {{cs-IPA}}
* {{audio|cs|LL-Q9056 (ces)-Ghost4Man-{{pagename}}.wav}}
===ကြိယာ===
{{cs-verb|a=impf|pf=rozzlobit}}
# သကဵုဂတာတ်၊ သကဵုလဳလှန်ဗ္ဂေတ်လ္ပာ်နာနာသာ်။
#: {{syn|cs|štvát|vadit}}
# ပရေၚ်ဟီုဂးဂလာန်သာ်ဂှ်။
#: {{syn|cs|škádlit}}
# သကဵုခ္ဍုတ်လဒါ်တိုန်။
# သကဵုဒှ်စိုတ်က္ကဵု။
#: {{syn|cs|[[hněvat|hněvat se]]}}
====သမ္ဗန္ဓ====
{{cs-conj-pros-it|zl|o|b|aspect=i|pass=no}}
k7buej2vf5gecyw512vciexsl2hkbh9
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၅
4
297644
399970
2026-07-23T10:03:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|zlobit|ကြိယာ| သကဵုဂတာတ်၊ သကဵုလဳလှန်ဗ္ဂေတ်လ္ပာ်နာနာသာ်။ #: {{syn|cs|štvát|vadit}} # ပရေၚ်ဟီုဂးဂလာန်သာ်ဂှ်။ #: {{syn|cs|škádlit}} # သကဵုခ္ဍုတ်လဒါ်တိုန်။ # သကဵုဒှ်စိုတ်က္ကဵု။ #: {{syn|cs|hněvat|hněvat..."
399970
wikitext
text/x-wiki
{{WOTD|zlobit|ကြိယာ| သကဵုဂတာတ်၊ သကဵုလဳလှန်ဗ္ဂေတ်လ္ပာ်နာနာသာ်။
#: {{syn|cs|štvát|vadit}}
# ပရေၚ်ဟီုဂးဂလာန်သာ်ဂှ်။
#: {{syn|cs|škádlit}}
# သကဵုခ္ဍုတ်လဒါ်တိုန်။
# သကဵုဒှ်စိုတ်က္ကဵု။
#: {{syn|cs|[[hněvat|hněvat se]]}}|audio=LL-Q9056 (ces)-Ghost4Man-zlobit.wav|ဂျူလာင်|၂၅}}
f6jozq32hqeuvxia542nkh49f5opfxl
ထာမ်ပလိက်:cs-conj-pros-it
10
297645
399971
2026-07-23T10:05:08Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|warn}}<!-- Validate template parameters -->{{cs-conj-forms |vn={{#if:{{{vn|}}}|{{{vn}}}|{{#if:{{{pass|}}}|{{#ifeq:{{{pass}}}|no| {{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}štění|zd={{{1|}}}{{{2|}}}ždění| {{#switch:{{{2|}}}|a|á|e|é|ě|o|ó|ou|u|y|ý|l|r={{#switch:{{{3|}}}| s={{{1|}}}{{{2|}}}šení|z={{#ifeq:{{{2|}}}|e|{{{1|}}}{{{2|}}}{{{3..."
399971
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
-->{{cs-conj-forms
|vn={{#if:{{{vn|}}}|{{{vn}}}|{{#if:{{{pass|}}}|{{#ifeq:{{{pass}}}|no|
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}štění|zd={{{1|}}}{{{2|}}}ždění|
{{#switch:{{{2|}}}|a|á|e|é|ě|o|ó|ou|u|y|ý|l|r={{#switch:{{{3|}}}|
s={{{1|}}}{{{2|}}}šení|z={{#ifeq:{{{2|}}}|e|{{{1|}}}{{{2|}}}{{{3|}}}ení|{{{1|}}}{{{2|}}}žení}}|t={{{1|}}}{{{2|}}}cení|n={{{1|}}}{{{2|}}}nění|d={{#ifeq:{{{2|}}}|ě|{{{1|}}}{{{2|}}}dění|{{{1|}}}{{{2|}}}zení}} |{{{1|}}}{{{2|}}}{{{3|}}}ení }} |
{{#switch:{{{3|}}}|d|t|n={{{1|}}}{{{2|}}}{{{3|}}}ění| {{{1|}}}{{{2|}}}{{{3|}}}ení}} }} }}|{{{pass|}}}í}}|{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}štění|zd={{{1|}}}{{{2|}}}ždění|
{{#switch:{{{2|}}}|a|á|e|é|ě|o|ó|ou|u|y|ý|l|r={{#switch:{{{3|}}}|
s={{{1|}}}{{{2|}}}šení|z={{#ifeq:{{{2|}}}|e|{{{1|}}}{{{2|}}}{{{3|}}}ení|{{{1|}}}{{{2|}}}žení}}|t={{{1|}}}{{{2|}}}cení|n={{{1|}}}{{{2|}}}nění|d={{#ifeq:{{{2|}}}|ě|{{{1|}}}{{{2|}}}dění|{{{1|}}}{{{2|}}}zení}} |{{{1|}}}{{{2|}}}{{{3|}}}ení }} |
{{#switch:{{{3|}}}|d|t|n={{{1|}}}{{{2|}}}{{{3|}}}ění| {{{1|}}}{{{2|}}}{{{3|}}}ení}} }} }} }} }}
|pass adj={{#ifeq:{{{pass|}}}|no||
{{#if:{{{pass adj|}}}|{{{pass adj}}}|{{#if:{{{pass|}}}|{{{pass|}}}ý|
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}štěný|zd={{{1|}}}{{{2|}}}žděný|
{{#switch:{{{2|}}}|a|á|e|é|ě|o|ó|ou|u|y|ý|l|r={{#switch:{{{3|}}}|
s={{{1|}}}{{{2|}}}šený|z={{#ifeq:{{{2|}}}|e|{{{1|}}}{{{2|}}}{{{3|}}}ený|{{{1|}}}{{{2|}}}žený}}|t={{{1|}}}{{{2|}}}cený|n={{{1|}}}{{{2|}}}něný|d={{#ifeq:{{{2|}}}|ě|{{{1|}}}{{{2|}}}děný|{{{1|}}}{{{2|}}}zený}} |{{{1|}}}{{{2|}}}{{{3|}}}ený }} |
{{#switch:{{{3|}}}|d|t|n={{{1|}}}{{{2|}}}{{{3|}}}ěný| {{{1|}}}{{{2|}}}{{{3|}}}ený}} }} }} }} }} }}
|pf 3s={{{1|}}}{{{2|}}}{{{3|}}}í
|im 2s={{#if:{{{im 2s|}}}|{{{im 2s}}} |
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}sť |zd={{{1|}}}{{{2|}}}zdi |
{{#switch:{{{2|}}}|a|á|e|é|ě|i|í|o|ó|u|ú|ů|y|ý|ou={{#switch:{{{3|}}}
|d={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ď
|t={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ť
|n={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ň
|{{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ú|ů|ou=u|{{{2|}}} }}{{{3|}}} }}
|{{{1|}}}{{{2|}}}{{{3|}}}i}} }} }}
|im 2s2={{#if:{{{im 2s2|}}}|{{{im 2s2}}}|{{#ifeq:{{{3|}}}|ř|{{#ifeq:{{{2|}}}|t|{{{1|}}}{{{2|}}}{{{3|}}} }} }} }}
|im 2s col={{#if:{{{im col|}}}|{{{im col}}} }}
|im 1p={{#if:{{{im 1p|}}}|{{{im 1p}}}|{{#if:{{{im 2s|}}}|{{{im 2s}}}me |
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}sťme | zd={{{1|}}}{{{2|}}}zděme |
{{#switch:{{{2|}}}|a|á|e|é|ě|i|í|o|ó|u|ú|ů|y|ý|ou={{#switch:{{{3|}}}
|d={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ďme
|t={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ťme
|n={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ňme
|{{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ú|ů|ou=u|{{{2|}}} }}{{{3|}}}me}}
|{{#switch:{{{3|}}}|b|d|m|n|p|t|v={{{1|}}}{{{2|}}}{{{3|}}}ěme | {{{1|}}}{{{2|}}}{{{3|}}}eme }} }} }} }} }}
|im 1p2={{#if:{{{im 1p2|}}}|{{{im 1p2}}}|{{#if:{{{im 2s2|}}}|{{#ifeq:{{{im 2s2|}}}|{{{1|}}}{{{2|}}}{{{3|}}}i|{{#switch:{{{3|}}}|b|d|m|n|p|t|st|v|zd={{{1|}}}{{{2|}}}{{{3|}}}ěme | {{{1|}}}{{{2|}}}{{{3|}}}eme }}|{{{im 2s2}}}me }} }} }}
|im 2p={{#if:{{{im 2p|}}}|{{{im 2p}}} | {{#if:{{{im 2s|}}}|{{{im 2s}}}te |
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}sťte | zd={{{1|}}}{{{2|}}}zděte|
{{#switch:{{{2|}}}|a|á|e|é|ě|i|í|o|ó|u|ú|ů|y|ý|ou={{#switch:{{{3|}}}
|d={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ďte
|t={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ťte
|n={{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ou=u|{{{2|}}} }}ňte
|{{{1|}}}{{#switch:{{{2|}}}|á=a|é=e|í=i|ý=y|ú|ů|ou=u|{{{2|}}} }}{{{3|}}}te}}
|{{#switch:{{{3|}}}|b|d|m|n|p|t|v={{{1|}}}{{{2|}}}{{{3|}}}ěte | {{{1|}}}{{{2|}}}{{{3|}}}ete }} }} }} }} }}
|im 2p2={{#if:{{{im 2p2|}}}|{{{im 2p2}}}|{{#if:{{{im 2s2|}}}|{{#ifeq:{{{im 2s2|}}}|{{{1|}}}{{{2|}}}{{{3|}}}i|{{#switch:{{{3|}}}|b|d|m|n|p|t|st|v|zd={{{1|}}}{{{2|}}}{{{3|}}}ěte | {{{1|}}}{{{2|}}}{{{3|}}}ete }}|{{{im 2s2}}}te }} }} }}
|past ms={{#if:{{{past|}}}|{{{past}}}|{{{1|}}}{{{2|}}}{{{3|}}}il}}
|past ms2={{#if:{{{past2|}}}|{{{past2}}} }}
|pass ms={{#ifeq:{{{pass|}}}|no||
{{#if:{{{pass|}}}|{{{pass}}} |
{{#switch:{{{3|}}}|st={{{1|}}}{{{2|}}}štěn|zd={{{1|}}}{{{2|}}}žděn|
{{#switch:{{{2|}}}|a|á|e|é|ě|o|ó|ou|u|y|ý|l|r={{#switch:{{{3|}}}|
s={{{1|}}}{{{2|}}}šen|z={{#ifeq:{{{2|}}}|e|{{{1|}}}{{{2|}}}{{{3|}}}en|{{{1|}}}{{{2|}}}žen}}|t={{{1|}}}{{{2|}}}cen|n={{{1|}}}{{{2|}}}něn|d={{#ifeq:{{{2|}}}|ě|{{{1|}}}{{{2|}}}děn|{{{1|}}}{{{2|}}}zen}} |{{{1|}}}{{{2|}}}{{{3|}}}en }} |
{{#switch:{{{3|}}}|d|t|n={{{1|}}}{{{2|}}}{{{3|}}}ěn| {{{1|}}}{{{2|}}}{{{3|}}}en}} }} }} }} }}
|pass ms2={{#if:{{{pass2|}}}|{{{pass2}}} }}
|pass ns={{#ifeq:{{{pass ns|}}}|yes| {{#switch:{{{3|}}}|d|t|n={{{1|}}}{{{2|}}}{{{3|}}}ěno|{{{1|}}}{{{2|}}}{{{3|}}}eno}}|{{#if:{{{pass ns|}}}|{{{pass ns}}} }} }}
|pass ns2={{#if:{{{pass ns2|}}}|{{{pass ns2}}} }}
|tr1 pres={{#if:{{{tr1 pres|}}}|{{{tr1 pres}}}|{{#switch:{{{aspect|}}}|i|imp|impf|imperfect|imperfective|pf-impf|p-i|pi={{#if:{{{tr pres|}}}|{{{tr pres}}}|{{#switch:{{{3|}}}|d|t|b|m|n|p|v|st|zd={{{1|}}}{{{2|}}}{{{3|}}}ě|{{{1|}}}{{{2|}}}{{{3|}}}e }} }} }} }}
|tr2 pres={{#if:{{{tr2 pres|}}}|{{{tr2 pres}}}|{{#switch:{{{aspect|}}}|i|imp|impf|imperfect|imperfective|pf-impf|p-i|pi={{{1|}}}{{{2|}}}{{{3|}}}íc}} }}
|tr1 past={{#if:{{{tr past|}}}|{{{tr past}}}|{{#switch:{{{aspect|}}}|i|imp|impf|imperfect|imperfective=|{{{1|}}}{{{2|}}}{{{3|}}}iv}} }}
|tr1 past2={{#if:{{{tr past2|}}}|{{{tr past2}}} }}
|aspect={{#if:{{{aspect|}}}|{{{aspect}}}|pf}} }}<noinclude>{{documentation}}</noinclude>
eke8zebgzf75b3l837hwtzerd4jdzza
ထာမ်ပလိက်:cs-conj-pros-it/documentation
10
297646
399972
2026-07-23T10:07:15Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} <!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE --> ===Usage=== A template for displaying conjugation forms of Czech verbs of the pattern {{m|cs|prosit}}. ===Parameters=== {| class="wikitable" ! Parameter ! Meaning ! Note |- | 1 | base of the verb without the ending ''-it'' and without the last two letters of the base, for example ''pr'' for {{m|cs|prosit}}, or ''povzb..."
399972
wikitext
text/x-wiki
{{documentation subpage}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
===Usage===
A template for displaying conjugation forms of Czech verbs of the pattern {{m|cs|prosit}}.
===Parameters===
{| class="wikitable"
! Parameter
! Meaning
! Note
|-
| 1
| base of the verb without the ending ''-it'' and without the last two letters of the base, for example ''pr'' for {{m|cs|prosit}}, or ''povzb'' for {{m|cs|povzbudit}}
| Can be omitted, if the word is too short for all three parameters, such as {{m|cs|udit}}, see the example below.
|-
| 2
| the second letter from the end of the base of the verb, for example ''o'' for pr-o-s-it.
| Enables e. g. to shorten the letter in some imperatives, for example the imperative of {{m|cs|chránit}} is ''{{m|cs|chraň}}'' and to decide whether the imperative has the ending ''-i'' ({{m|cs|ovlivnit}} → {{m|cs|ovlivni}}) or not. See the examples below.
|-
| 3
| the last letter (exceptionally two letters) of the base of the verb, for example ''s'' for pr-o-s-it.
| Enables e. g. to decide whether the passive or present transgressive ending containts ''-e-'' or ''-ě-'', such as {{m|cs|věznit}} → passive {{m|cs|vězněn}}. It also enables to change the last letter of the base in some some passive forms, like {{m|cs|prosit}} → passive {{m|cs|prošen}}. Sometimes two letters ''st'' or ''zd'' can be filled, e. g. filling ''st'' in {{m|cs|zjistit}} (zj|i|st) results in the passive {{m|cs|zjištěn}}. See examples below.
|-
| aspect
| generates the note about future tense, which depends on the aspect of the verb and decides whether present or past transgressives are shown
| Possible values:
* the default value is perfective, so for [[perfective]] verbs it can be left out
* "imperfective" (or alternatively "imperfect", "impf", "imp" or "i") for [[imperfective]] verbs
* "pf-impf" (or alternatively "p-i" or "pi") – for verbs which can have both aspects
|-
| im 2s
| '''i'''mperative '''2'''nd person '''s'''ingular
| needed only if different from automatically generated form. If filled, generates automatically also 1st and 2nd person plural imperatives
|-
| im col
| colloquial form of the 2nd person singular imperative
| If filled generates automatically also colloquial forms of the 1st and 2nd person plural imperatives.
|-
| past
| alternative form of the past participle can be filled if it is different than the automatically generated form
|
|-
| past2
| another alternative form of the past participle can be filled if it exists
|
|-
| pass
| It can prevent the passive to be shown or alternative form of the passive can be filled
| The value "no" causes that no passives are filled if the verb does not have passive forms. Another option is to fill in a passive form if the verb has a different form of passive than the automatically generated one.
|-
| pass2
| another alternative form of the passive participle
|
|-
| pass ns
| passive neutral singular
| The value "yes" enables to show passive neutral singular form of the verb in cases when the verb does not form other passive voice forms, which are disabled by the parameter "pass".
|-
| pass ns2
| alternative passive neutral singular
| For practical usage see {{m|cs|hrozit}}
|-
| tr1 pres
| masculine present transgressive, usually not necessary to fill for imperfective verbs which form it simply by adding ''-e'' or ''-ě'' (fills automatically).
|
|-
| tr2 pres
| feminine present transgressive, usually not necessary to fill for imperfective verbs which form it simply by adding ''-íc'' (fills automatically); generates plural present transgressive too
|
|-
| tr past
| masculine past transgressive, usually not necessary to fill for perfective verbs which form it simply by adding ''-iv''; generates feminine and plural past transgressives too
|
|}
===Examples===
;For the verb {{m|cs|prosit}}
The letter ''s'' changes into ''š'' in passive forms automatically, Imperfective aspect needs to be indicated.
<pre>{{cs-conj-pros-it|pr|o|s|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|pr|o|s|aspect=i}}
;For the verb {{m|cs|překazit}}
The letter ''z'' changes into ''ž'' in passive forms automatically. Perfective aspect does not have to be indicated.
<pre>{{cs-conj-pros-it|přek|a|z}}</pre>
Result:
{{cs-conj-pros-it|přek|a|z}}
;For the verb {{m|cs|pročistit}}
Adding ''-st-'' into the third parameter results in passives with ''-št-''. Parameter "im 2s2" (='''im'''perative '''2'''nd person '''s'''ingular, '''2'''nd form), adds alternative passives, including the plural ones. (If needed, parameters "im 1p2" and "im 2p2" can be used too).
<pre>{{cs-conj-pros-it|proč|i|st|im 2s2=pročisti|pass2=pročistěn}}</pre>
Result:
{{cs-conj-pros-it|proč|i|st|im 2s2=pročisti|pass2=pročistěn}}
;For the verb {{m|cs|vyhlásit}}
Adding the parameter "im col" adds a colloquial version of the imperative.
<pre>{{cs-conj-pros-it|vyhl|á|s|im col=vyhlaš}}</pre>
Result:
{{cs-conj-pros-it|vyhl|á|s|im col=vyhlaš}}
;For the verb {{m|cs|jezdit}}
Adding ''-zd-'' into the third parameter results in passives with ''-žd-'', parameter pass2 can show also the alternative version with ''-zd-'' if it exists.
<pre>{{cs-conj-pros-it|j|e|zd|pass2=jezděn|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|j|e|zd|pass2=jezděn|aspect=i}}
;For the verb {{m|cs|hyzdit}}
If the letters ''zd'' are divided into the second and third parameter, they stay the same.
<pre>{{cs-conj-pros-it|hy|z|d|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|hy|z|d|aspect=i}}
;For the verb {{m|cs|oloupit}}
Filling the 2nd parameter with ''-ou-'' can display the imperative correctly for verbs like {{m|cs|koupit}} or {{m|cs|oloupit}}.
<pre>{{cs-conj-pros-it|ol|ou|p}}</pre>
Result:
{{cs-conj-pros-it|ol|ou|p}}
;For the verb {{m|cs|drtit}}
Adding the parameter "im 2s" (='''im'''perative '''2'''nd person '''s'''ingular) enables to show different imperative than the automatically generated (which would be non-existing ''*drti'' in this case).
<pre>{{cs-conj-pros-it|d|r|t|im 2s=drť|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|d|r|t|im 2s=drť|aspect=i}}
;For the verb {{m|cs|udit}}
Sometimes the verb is too short to fill all the first three parameters. In such a case the first parameter is left empty.
<pre>{{cs-conj-pros-it||u|d|aspect=i}}</pre>
Result:
{{cs-conj-pros-it||u|d|aspect=i}}
;For the verb {{m|cs|lišit}}
If the verb has no passive forms, the passive can be disabled by setting the parameter "pass" to "no":
<pre>{{cs-conj-pros-it|l|i|š|pass=no|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|l|i|š|pass=no|aspect=i}}
;For the verb {{m|cs|souhlasit}}
If the verb has no passive forms with the exception of neuter singular, the passive can be generally disabled and passive neuter singular enabled:
<pre>{{cs-conj-pros-it|souhl|a|s|pass=no|pass ns=yes|aspect=i}}</pre>
Result:
{{cs-conj-pros-it|souhl|a|s|pass=no|pass ns=yes|aspect=i}}
<includeonly><!-- CATEGORIES AND INTERWIKIS HERE, THANKS -->
[[ကဏ္ဍ:ထာမ်ပလိက်ချက်ခ်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်]]
</includeonly>
mj5bgmed4wa4mwb2litq7h2m4rbbh5b
ကဏ္ဍ:ထာမ်ပလိက်ချက်ခ်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်
14
297647
399973
2026-07-23T10:09:46Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ချက်ခ်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ခ]]"
399973
wikitext
text/x-wiki
[[ကဏ္ဍ:ထာမ်ပလိက်ချက်ခ်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ခ]]
6yrl7im8awx9tpowkgiw294cahr0anj
ထာမ်ပလိက်:cs-conj-forms
10
297648
399974
2026-07-23T10:30:48Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{#invoke:checkparams|warn}}<!-- Validate template parameters -->{{inflection-box-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|cs||{{pagename}}}}|flow=vertical}} {{inflection-table-top|palette=grey|title=-}} !ကြိယာဟွံကၠောံ |{{l|cs|2={{pagename}}}}, {{#if:{{{inf2|}}}|{{l|cs|2={{{inf2}}}}}|{{l|cs|2={{pagename}}i}}}} !နာမဝိသေသနမစိုပ်ရဴ |{{#i..."
399974
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
-->{{inflection-box-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|cs||{{pagename}}}}|flow=vertical}}
{{inflection-table-top|palette=grey|title=-}}
!ကြိယာဟွံကၠောံ
|{{l|cs|2={{pagename}}}}, {{#if:{{{inf2|}}}|{{l|cs|2={{{inf2}}}}}|{{l|cs|2={{pagename}}i}}}}
!နာမဝိသေသနမစိုပ်ရဴ
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}í}}|{{#if:{{{tr1 past|}}}||—}}}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}í}}|}}{{#if:{{{tr1 past|}}}|{{#if:{{{tr1 pres|}}}|, {{l|cs|2={{{tr1 past}}}ší}}|{{l|cs|2={{{tr1 past}}}ší}}}}|}}
{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ší}}|}}
{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ší}}|}}
|-
!နာမ်ပါၚ်တိုက်
|{{#if:{{{vn|}}}|{{l|cs|2={{{vn}}}}}|—}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}}
!နာမဝိသေသနမဒုၚ်ကေတ်
|{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|—}}|—}}{{#if:{{{pass ms2|}}}|{{#if:{{{pass adj2|}}}|, {{l|cs|2={{{pass adj2}}}}}|}}|}}{{#if:{{{pass ms3|}}}|{{#if:{{{pass adj3|}}}|, {{l|cs|2={{{pass adj3}}}}}|}}
|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | present forms !!colspan="2"|indicative !!colspan="2"|ပါဲဗလေတ်ဟွံဗၠး
|-
! !!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်!!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်
|-
!ပူဂဵုမရနုက်ကဵု ၂
|{{#if:{{{pf 1s|}}}|{{l|cs|2={{{pf 1s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}m}}|—}}}}{{#if:{{{pf 1s2|}}}|, {{l|cs|2={{{pf 1s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}m}} }}|}}}}{{#if:{{{pf 1s col|}}}|,<br/> {{l|cs|2={{{pf 1s col}}}}} (''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|—}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || — ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|—}}}}{{#if:{{{im 1p2|}}}|, {{l|cs|2={{{im 1p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}me}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}me}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၂
| {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|—}}}}{{#if:{{{pf 2s2|}}}|, {{l|cs|2={{{pf 2s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}š}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}š}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|—}}}}{{#if:{{{pf 2p2|}}}|, {{l|cs|2={{{pf 2p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}te}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}te}} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|—}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|—}} }}{{#if:{{{im 2p2|}}}|, {{l|cs|2={{{im 2p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}te}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}te}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၃
| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|—}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| —}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}} (''[[colloquial|coll.]]'')}} || — || —
{{#switch: {{{aspect}}}
|perfective|perfect|pf|p={{inflection-table-bottom|notes=The verb ''{{pagename}}'' does not have present tense and the present forms are used to express future only.}}
|imperfective|imperfect|impf|imp|i={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|negativeimperfective|nimpf|nimp|ni={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|pf-impf|p-i|pi={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|pf-nimpf|p-ni|pni={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|#default={{inflection-table-bottom}}
{{inflection-table-top|title=-|palette=grey}}
{{#switch: {{{future}}}
|po|pů|=! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{pf 1s|}}}|{{l|cs|2={{{future}}}{{{pf 1s}}}}}|{{l|cs|2={{{future}}}{{{pf 3s}}}m}} }}{{#if:{{{pf 1s col|}}}|, {{l|cs|2={{{future}}}{{{pf 1s col}}}}} (''[[colloquial|coll.]]'') }}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}me }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}š}}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}te}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}}}
{{!}} {{l|cs|2={{{future}}}{{#if:{{{pf 3p|}}}|{{{pf 3p}}}|{{{pf 3s}}} }} }}{{#if:{{{pf 3p col|}}}|, {{l|cs|2={{{future}}}{{{pf 3p col}}}}} (''[[colloquial|coll.]]'') }}
|#default ={{#ifeq: {{{future}}} | bud |
! class="outer {{!}}
! class="outer" colspan="2" {{!}} ဗီုပြၚ်အနာဂတ်
! class="outer" colspan="2" {{!}} ဗီုပြၚ်တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်
{{!}}-
!
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{l|cs|budu}}
{{!}} {{l|cs|budeme}}
{{!}} {{l|cs|bych}}
{{!}} {{l|cs|bychom}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|budeš}}
{{!}} {{l|cs|budete}}
{{!}} {{l|cs|bys}}
{{!}} {{l|cs|byste}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|bude}}
{{!}} {{l|cs|budou}}
{{!}} {{l|cs|by}}
{{!}} {{l|cs|by}}| {{#if:{{{ff 3s|}}}|
! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{ff 1s|}}} | {{l|cs|2={{{ff 1s}}} }} | {{#if:{{{ff 3s|}}} | {{l|cs|2={{{ff 3s}}}m}} | {{l|cs|2={{{future}}}u}} }} }}{{#if:{{{ff 1s col|}}} |, {{l|cs|2={{{ff 1s col}}} }} (''[[colloquial|coll.]]'') }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}me}} |{{l|cs|2={{{future}}}eme}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}š}} |{{l|cs|2={{{future}}}eš}} }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}te}} |{{l|cs|2={{{future}}}ete}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }}|{{l|cs|2={{{future}}}e}} }}
{{!}} {{#if:{{{ff 3p|}}}|{{l|cs|2={{{ff 3p}}} }}|{{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }} | {{l|cs|2={{{future}}}ou}} }} }}{{#if:{{{ff 3p col|}}} |, {{l|cs|2={{{ff 3p col}}} }} (''[[colloquial|coll.]]'') }} }} }} }}
{{inflection-table-bottom}}
}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | participles !!colspan="2" |past participles!! colspan="2" |လုပ်ကၠောန်စွံလဝ်မဒုၚ်ကေတ်
|-
! !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ် !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ်
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}}}|—}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}}}|}} ||{{#if:{{{past map|}}}|{{l|cs|2={{{past map}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}i}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}i}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}i}}|}}|| rowspan="2" | {{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}}}|—}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}}}|}} ||{{#if:{{{pass map|}}}|{{l|cs|2={{{pass map}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}i}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}i}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}i}}|}}
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past mifp|}}}|{{l|cs|2={{{past mifp}}}}}| {{#if:{{{past fp|}}}|{{l|cs|2={{{past fp}}}}}|{{#if:{{{past mip|}}}|{{l|cs|2={{{past mip}}}}}|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}y}}|—}}}}}}}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}y}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}y}}|}} ||rowspan="2"|{{#if:{{{pass mifp|}}}|{{l|cs|2={{{pass mifp}}}}}| {{#if:{{{pass fp|}}}|{{l|cs|2={{{pass fp}}}}}|{{#if:{{{pass mip|}}}|{{l|cs|2={{{pass mip}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}y}}|—}}}}}}}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}y}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}y}}|}}
|-
!ဣတ္တိလိၚ်
|{{#if:{{{past fs|}}}|{{l|cs|2={{{past fs}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}|—}} }}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} ||{{#if:{{{pass fs|}}}|{{l|cs|2={{{pass fs}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
|-
!နပုလ္လိၚ်
|{{#if:{{{past ns|}}}|{{l|cs|2={{{past ns}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}o}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}o}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}o}}|}} || {{#if:{{{past np|}}}|{{l|cs|2={{{past np}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} || {{#if:{{{pass ns|}}}|{{l|cs|2={{{pass ns}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}o}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}o}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}o}}|}}{{#if:{{{pass ns2|}}}|, {{l|cs|2={{{pass ns2}}} }}|}} ||{{#if:{{{pass np|}}}|{{l|cs|2={{{pass np}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | ညးမကၠောံၜက်
!ပစ္စုပ္ပန်
!အတိက်
|-
! ကိုန်ဨကဝုစ်ပုလ္လိၚ်
| {{#if:{{{tr1 pres|}}}|{{l|cs|2={{{tr1 pres}}}}}|—}}{{#if:{{{tr1 pres2|}}}|, {{l|cs|2={{{tr1 pres2}}}}}|}} || {{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}}}|}}|—}}
|-
!ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ်
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|—}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}}}|}} || {{#if:{{{tr2 past|}}}|{{l|cs|2={{{tr2 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}ši}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ši}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ši}}|}}|—}} }}
|-
!ကိုန်ဗဟုဝစ်
| {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|—}} }}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}e}}|}} || {{#if:{{{tr3 past|}}}|{{l|cs|2={{{tr3 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}še}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}še}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}še}}|}}|—}} }}
|}</div>{{#ifeq: {{NAMESPACE}} | {{NS: 0 }} | {{#switch: {{{aspect}}} | pf-impf|p-i|pi= }} }}
{{inflection-box-bottom}}<noinclude>{{documentation}}</noinclude>
t36qh4tw91indr3c71f038qryn414b1
399975
399974
2026-07-23T10:36:43Z
咽頭べさ
33
399975
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
-->{{inflection-box-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|cs||{{pagename}}}}|flow=vertical}}
{{inflection-table-top|palette=grey|title=-}}
!ကြိယာဟွံကၠောံ
|{{l|cs|2={{pagename}}}}, {{#if:{{{inf2|}}}|{{l|cs|2={{{inf2}}}}}|{{l|cs|2={{pagename}}i}}}}
!နာမဝိသေသနမစိုပ်ရဴ
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}í}}|{{#if:{{{tr1 past|}}}||—}}}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}í}}|}}{{#if:{{{tr1 past|}}}|{{#if:{{{tr1 pres|}}}|, {{l|cs|2={{{tr1 past}}}ší}}|{{l|cs|2={{{tr1 past}}}ší}}}}|}}
{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ší}}|}}
{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ší}}|}}
|-
!နာမ်ပါၚ်တိုက်
|{{#if:{{{vn|}}}|{{l|cs|2={{{vn}}}}}|—}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}}
!နာမဝိသေသနမဒုၚ်ကေတ်
|{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|—}}|—}}{{#if:{{{pass ms2|}}}|{{#if:{{{pass adj2|}}}|, {{l|cs|2={{{pass adj2}}}}}|}}|}}{{#if:{{{pass ms3|}}}|{{#if:{{{pass adj3|}}}|, {{l|cs|2={{{pass adj3}}}}}|}}
|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | ဗီုပြၚ်ပစ္စုပ္ပန် !!colspan="2"|ပရေၚ်စၞောန်ထ္ၜး !!colspan="2"|ပါဲဗလေတ်ဟွံဗၠး
|-
! !!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်!!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်
|-
!ပူဂဵုမရနုက်ကဵု ၂
|{{#if:{{{pf 1s|}}}|{{l|cs|2={{{pf 1s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}m}}|—}}}}{{#if:{{{pf 1s2|}}}|, {{l|cs|2={{{pf 1s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}m}} }}|}}}}{{#if:{{{pf 1s col|}}}|,<br/> {{l|cs|2={{{pf 1s col}}}}} (''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|—}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || — ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|—}}}}{{#if:{{{im 1p2|}}}|, {{l|cs|2={{{im 1p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}me}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}me}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၂
| {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|—}}}}{{#if:{{{pf 2s2|}}}|, {{l|cs|2={{{pf 2s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}š}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}š}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|—}}}}{{#if:{{{pf 2p2|}}}|, {{l|cs|2={{{pf 2p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}te}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}te}} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|—}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|—}} }}{{#if:{{{im 2p2|}}}|, {{l|cs|2={{{im 2p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}te}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}te}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၃
| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|—}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| —}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}} (''[[colloquial|coll.]]'')}} || — || —
{{#switch: {{{aspect}}}
|perfective|perfect|pf|p={{inflection-table-bottom|notes=The verb ''{{pagename}}'' does not have present tense and the present forms are used to express future only.}}
|imperfective|imperfect|impf|imp|i={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|negativeimperfective|nimpf|nimp|ni={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|pf-impf|p-i|pi={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|pf-nimpf|p-ni|pni={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|#default={{inflection-table-bottom}}
{{inflection-table-top|title=-|palette=grey}}
{{#switch: {{{future}}}
|po|pů|=! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{pf 1s|}}}|{{l|cs|2={{{future}}}{{{pf 1s}}}}}|{{l|cs|2={{{future}}}{{{pf 3s}}}m}} }}{{#if:{{{pf 1s col|}}}|, {{l|cs|2={{{future}}}{{{pf 1s col}}}}} (''[[colloquial|coll.]]'') }}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}me }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}š}}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}te}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}}}
{{!}} {{l|cs|2={{{future}}}{{#if:{{{pf 3p|}}}|{{{pf 3p}}}|{{{pf 3s}}} }} }}{{#if:{{{pf 3p col|}}}|, {{l|cs|2={{{future}}}{{{pf 3p col}}}}} (''[[colloquial|coll.]]'') }}
|#default ={{#ifeq: {{{future}}} | bud |
! class="outer {{!}}
! class="outer" colspan="2" {{!}} ဗီုပြၚ်အနာဂတ်
! class="outer" colspan="2" {{!}} ဗီုပြၚ်တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်
{{!}}-
!
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{l|cs|budu}}
{{!}} {{l|cs|budeme}}
{{!}} {{l|cs|bych}}
{{!}} {{l|cs|bychom}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|budeš}}
{{!}} {{l|cs|budete}}
{{!}} {{l|cs|bys}}
{{!}} {{l|cs|byste}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|bude}}
{{!}} {{l|cs|budou}}
{{!}} {{l|cs|by}}
{{!}} {{l|cs|by}}| {{#if:{{{ff 3s|}}}|
! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{ff 1s|}}} | {{l|cs|2={{{ff 1s}}} }} | {{#if:{{{ff 3s|}}} | {{l|cs|2={{{ff 3s}}}m}} | {{l|cs|2={{{future}}}u}} }} }}{{#if:{{{ff 1s col|}}} |, {{l|cs|2={{{ff 1s col}}} }} (''[[colloquial|coll.]]'') }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}me}} |{{l|cs|2={{{future}}}eme}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}š}} |{{l|cs|2={{{future}}}eš}} }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}te}} |{{l|cs|2={{{future}}}ete}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }}|{{l|cs|2={{{future}}}e}} }}
{{!}} {{#if:{{{ff 3p|}}}|{{l|cs|2={{{ff 3p}}} }}|{{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }} | {{l|cs|2={{{future}}}ou}} }} }}{{#if:{{{ff 3p col|}}} |, {{l|cs|2={{{ff 3p col}}} }} (''[[colloquial|coll.]]'') }} }} }} }}
{{inflection-table-bottom}}
}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | participles !!colspan="2" |past participles!! colspan="2" |လုပ်ကၠောန်စွံလဝ်မဒုၚ်ကေတ်
|-
! !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ် !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ်
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}}}|—}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}}}|}} ||{{#if:{{{past map|}}}|{{l|cs|2={{{past map}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}i}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}i}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}i}}|}}|| rowspan="2" | {{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}}}|—}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}}}|}} ||{{#if:{{{pass map|}}}|{{l|cs|2={{{pass map}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}i}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}i}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}i}}|}}
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past mifp|}}}|{{l|cs|2={{{past mifp}}}}}| {{#if:{{{past fp|}}}|{{l|cs|2={{{past fp}}}}}|{{#if:{{{past mip|}}}|{{l|cs|2={{{past mip}}}}}|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}y}}|—}}}}}}}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}y}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}y}}|}} ||rowspan="2"|{{#if:{{{pass mifp|}}}|{{l|cs|2={{{pass mifp}}}}}| {{#if:{{{pass fp|}}}|{{l|cs|2={{{pass fp}}}}}|{{#if:{{{pass mip|}}}|{{l|cs|2={{{pass mip}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}y}}|—}}}}}}}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}y}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}y}}|}}
|-
!ဣတ္တိလိၚ်
|{{#if:{{{past fs|}}}|{{l|cs|2={{{past fs}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}|—}} }}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} ||{{#if:{{{pass fs|}}}|{{l|cs|2={{{pass fs}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
|-
!နပုလ္လိၚ်
|{{#if:{{{past ns|}}}|{{l|cs|2={{{past ns}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}o}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}o}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}o}}|}} || {{#if:{{{past np|}}}|{{l|cs|2={{{past np}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} || {{#if:{{{pass ns|}}}|{{l|cs|2={{{pass ns}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}o}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}o}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}o}}|}}{{#if:{{{pass ns2|}}}|, {{l|cs|2={{{pass ns2}}} }}|}} ||{{#if:{{{pass np|}}}|{{l|cs|2={{{pass np}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | ညးမကၠောံၜက်
!ပစ္စုပ္ပန်
!အတိက်
|-
! ကိုန်ဨကဝုစ်ပုလ္လိၚ်
| {{#if:{{{tr1 pres|}}}|{{l|cs|2={{{tr1 pres}}}}}|—}}{{#if:{{{tr1 pres2|}}}|, {{l|cs|2={{{tr1 pres2}}}}}|}} || {{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}}}|}}|—}}
|-
!ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ်
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|—}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}}}|}} || {{#if:{{{tr2 past|}}}|{{l|cs|2={{{tr2 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}ši}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ši}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ši}}|}}|—}} }}
|-
!ကိုန်ဗဟုဝစ်
| {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|—}} }}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}e}}|}} || {{#if:{{{tr3 past|}}}|{{l|cs|2={{{tr3 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}še}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}še}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}še}}|}}|—}} }}
|}</div>{{#ifeq: {{NAMESPACE}} | {{NS: 0 }} | {{#switch: {{{aspect}}} | pf-impf|p-i|pi= }} }}
{{inflection-box-bottom}}<noinclude>{{documentation}}</noinclude>
foxb0nhi1hugf2txrd2f1ydxcey2mcv
399976
399975
2026-07-23T10:42:50Z
咽頭べさ
33
399976
wikitext
text/x-wiki
{{#invoke:checkparams|warn}}<!-- Validate template parameters
-->{{inflection-box-top|title=သမ္ဗန္ဓဆေၚ်စပ်ကဵု {{m|cs||{{pagename}}}}|flow=vertical}}
{{inflection-table-top|palette=grey|title=-}}
!ကြိယာဟွံကၠောံ
|{{l|cs|2={{pagename}}}}, {{#if:{{{inf2|}}}|{{l|cs|2={{{inf2}}}}}|{{l|cs|2={{pagename}}i}}}}
!နာမဝိသေသနမစိုပ်ရဴ
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}í}}|{{#if:{{{tr1 past|}}}||—}}}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}í}}|}}{{#if:{{{tr1 past|}}}|{{#if:{{{tr1 pres|}}}|, {{l|cs|2={{{tr1 past}}}ší}}|{{l|cs|2={{{tr1 past}}}ší}}}}|}}
{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ší}}|}}
{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ší}}|}}
|-
!နာမ်ပါၚ်တိုက်
|{{#if:{{{vn|}}}|{{l|cs|2={{{vn}}}}}|—}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}}
!နာမဝိသေသနမဒုၚ်ကေတ်
|{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|—}}|—}}{{#if:{{{pass ms2|}}}|{{#if:{{{pass adj2|}}}|, {{l|cs|2={{{pass adj2}}}}}|}}|}}{{#if:{{{pass ms3|}}}|{{#if:{{{pass adj3|}}}|, {{l|cs|2={{{pass adj3}}}}}|}}
|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | ဗီုပြၚ်ပစ္စုပ္ပန် !!colspan="2"|ပရေၚ်စၞောန်ထ္ၜး !!colspan="2"|ပါဲဗလေတ်ဟွံဗၠး
|-
! !!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်!!ကိုန်ဨကဝုစ်!!ကိုန်ဗဟုဝစ်
|-
!ပူဂဵုမရနုက်ကဵု ၂
|{{#if:{{{pf 1s|}}}|{{l|cs|2={{{pf 1s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}m}}|—}}}}{{#if:{{{pf 1s2|}}}|, {{l|cs|2={{{pf 1s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}m}} }}|}}}}{{#if:{{{pf 1s col|}}}|,<br/> {{l|cs|2={{{pf 1s col}}}}} (''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|—}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || — ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|—}}}}{{#if:{{{im 1p2|}}}|, {{l|cs|2={{{im 1p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}me}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}me}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၂
| {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|—}}}}{{#if:{{{pf 2s2|}}}|, {{l|cs|2={{{pf 2s2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}š}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}š}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|—}}}}{{#if:{{{pf 2p2|}}}|, {{l|cs|2={{{pf 2p2}}}}}|
{{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}te}} }}|}}}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}te}} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|—}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }} (''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|—}} }}{{#if:{{{im 2p2|}}}|, {{l|cs|2={{{im 2p2}}}}}|{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}te}}|}} }}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}}te}} (''[[colloquial|coll.]]'')}}
|-
!ပူဂဵုမရနုက်ကဵု ၃
| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|—}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}} (''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| —}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}} (''[[colloquial|coll.]]'')}} || — || —
{{#switch: {{{aspect}}}
|perfective|perfect|pf|p={{inflection-table-bottom|notes=The verb ''{{pagename}}'' does not have present tense and the present forms are used to express future only.}}
|imperfective|imperfect|impf|imp|i={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|negativeimperfective|nimpf|nimp|ni={{inflection-table-bottom|notes=The future tense: a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|pf-impf|p-i|pi={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|být}} + infinitive ''{{pagename}}''.}}
|pf-nimpf|p-ni|pni={{inflection-table-bottom|notes=When the verb is used in [[perfective aspect]], it does not have present tense and the present forms are used to express future only.<br/>When the verb is used in [[imperfective aspect]], the future tense is a combination of a future form of {{m|cs|nebýt}} + infinitive of the positive form ''{{l|cs|2={{{positive}}}}}''.}}
|#default={{inflection-table-bottom}}
{{inflection-table-top|title=-|palette=grey}}
{{#switch: {{{future}}}
|po|pů|=! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{pf 1s|}}}|{{l|cs|2={{{future}}}{{{pf 1s}}}}}|{{l|cs|2={{{future}}}{{{pf 3s}}}m}} }}{{#if:{{{pf 1s col|}}}|, {{l|cs|2={{{future}}}{{{pf 1s col}}}}} (''[[colloquial|coll.]]'') }}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}me }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}š}}
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}te}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|2={{{future}}}{{{pf 3s}}}}}
{{!}} {{l|cs|2={{{future}}}{{#if:{{{pf 3p|}}}|{{{pf 3p}}}|{{{pf 3s}}} }} }}{{#if:{{{pf 3p col|}}}|, {{l|cs|2={{{future}}}{{{pf 3p col}}}}} (''[[colloquial|coll.]]'') }}
|#default ={{#ifeq: {{{future}}} | bud |
! class="outer {{!}}
! class="outer" colspan="2" {{!}} ဗီုပြၚ်အနာဂတ်
! class="outer" colspan="2" {{!}} ဗီုပြၚ်တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်
{{!}}-
!
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{l|cs|budu}}
{{!}} {{l|cs|budeme}}
{{!}} {{l|cs|bych}}
{{!}} {{l|cs|bychom}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{l|cs|budeš}}
{{!}} {{l|cs|budete}}
{{!}} {{l|cs|bys}}
{{!}} {{l|cs|byste}}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{l|cs|bude}}
{{!}} {{l|cs|budou}}
{{!}} {{l|cs|by}}
{{!}} {{l|cs|by}}| {{#if:{{{ff 3s|}}}|
! class="outer" {{!}} ဗီုပြၚ်အနာဂတ်
! ကိုန်ဨကဝုစ်
! ကိုန်ဗဟုဝစ်
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၁
{{!}} {{#if:{{{ff 1s|}}} | {{l|cs|2={{{ff 1s}}} }} | {{#if:{{{ff 3s|}}} | {{l|cs|2={{{ff 3s}}}m}} | {{l|cs|2={{{future}}}u}} }} }}{{#if:{{{ff 1s col|}}} |, {{l|cs|2={{{ff 1s col}}} }} (''[[colloquial|coll.]]'') }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}me}} |{{l|cs|2={{{future}}}eme}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၂
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}š}} |{{l|cs|2={{{future}}}eš}} }}
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}}te}} |{{l|cs|2={{{future}}}ete}} }}
{{!}}-
! ပူဂဵုမရနုက်ကဵု ၃
{{!}} {{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }}|{{l|cs|2={{{future}}}e}} }}
{{!}} {{#if:{{{ff 3p|}}}|{{l|cs|2={{{ff 3p}}} }}|{{#if:{{{ff 3s|}}}| {{l|cs|2={{{ff 3s}}} }} | {{l|cs|2={{{future}}}ou}} }} }}{{#if:{{{ff 3p col|}}} |, {{l|cs|2={{{ff 3p col}}} }} (''[[colloquial|coll.]]'') }} }} }} }}
{{inflection-table-bottom}}
}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | လုပ်ကၠောန်စွံလဝ် !!colspan="2" |လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်!! colspan="2" |လုပ်ကၠောန်စွံလဝ်မဒုၚ်ကေတ်
|-
! !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ် !!ကိုန်ဨကဝုစ် !!ကိုန်ဗဟုဝစ်
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}}}|—}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}}}|}} ||{{#if:{{{past map|}}}|{{l|cs|2={{{past map}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}i}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}i}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}i}}|}}|| rowspan="2" | {{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}}}|—}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}}}|}} ||{{#if:{{{pass map|}}}|{{l|cs|2={{{pass map}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}i}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}i}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}i}}|}}
|-
!ပုလ္လိၚ်သက္ကုဟၟဲကဵုလမျီု
|rowspan="2"|{{#if:{{{past mifp|}}}|{{l|cs|2={{{past mifp}}}}}| {{#if:{{{past fp|}}}|{{l|cs|2={{{past fp}}}}}|{{#if:{{{past mip|}}}|{{l|cs|2={{{past mip}}}}}|{{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}y}}|—}}}}}}}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}y}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}y}}|}} ||rowspan="2"|{{#if:{{{pass mifp|}}}|{{l|cs|2={{{pass mifp}}}}}| {{#if:{{{pass fp|}}}|{{l|cs|2={{{pass fp}}}}}|{{#if:{{{pass mip|}}}|{{l|cs|2={{{pass mip}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}y}}|—}}}}}}}}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}y}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}y}}|}}
|-
!ဣတ္တိလိၚ်
|{{#if:{{{past fs|}}}|{{l|cs|2={{{past fs}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}|—}} }}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} ||{{#if:{{{pass fs|}}}|{{l|cs|2={{{pass fs}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
|-
!နပုလ္လိၚ်
|{{#if:{{{past ns|}}}|{{l|cs|2={{{past ns}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}o}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}o}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}o}}|}} || {{#if:{{{past np|}}}|{{l|cs|2={{{past np}}}}}| {{#if:{{{past ms|}}}|{{l|cs|2={{{past ms}}}a}}|—}} }}{{#if:{{{past ms2|}}}|, {{l|cs|2={{{past ms2}}}a}}|}}{{#if:{{{past ms3|}}}|, {{l|cs|2={{{past ms3}}}a}}|}} || {{#if:{{{pass ns|}}}|{{l|cs|2={{{pass ns}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}o}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}o}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}o}}|}}{{#if:{{{pass ns2|}}}|, {{l|cs|2={{{pass ns2}}} }}|}} ||{{#if:{{{pass np|}}}|{{l|cs|2={{{pass np}}}}}|{{#if:{{{pass ms|}}}|{{l|cs|2={{{pass ms}}}a}}|—}} }}{{#if:{{{pass ms2|}}}|, {{l|cs|2={{{pass ms2}}}a}}|}}{{#if:{{{pass ms3|}}}|, {{l|cs|2={{{pass ms3}}}a}}|}}
{{inflection-table-bottom}}
{{inflection-table-top|palette=grey|title=-}}
! class="outer" | ညးမကၠောံၜက်
!ပစ္စုပ္ပန်
!အတိက်
|-
! ကိုန်ဨကဝုစ်ပုလ္လိၚ်
| {{#if:{{{tr1 pres|}}}|{{l|cs|2={{{tr1 pres}}}}}|—}}{{#if:{{{tr1 pres2|}}}|, {{l|cs|2={{{tr1 pres2}}}}}|}} || {{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}}}|}}|—}}
|-
!ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ်
|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|—}}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}}}|}} || {{#if:{{{tr2 past|}}}|{{l|cs|2={{{tr2 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}ši}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}ši}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}ši}}|}}|—}} }}
|-
!ကိုန်ဗဟုဝစ်
| {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|—}} }}{{#if:{{{tr2 pres2|}}}|, {{l|cs|2={{{tr2 pres2}}}e}}|}} || {{#if:{{{tr3 past|}}}|{{l|cs|2={{{tr3 past}}}}}|{{#if:{{{tr1 past|}}}|{{l|cs|2={{{tr1 past}}}še}}{{#if:{{{tr1 past2|}}}|, {{l|cs|2={{{tr1 past2}}}še}}|}}{{#if:{{{tr1 past3|}}}|, {{l|cs|2={{{tr1 past3}}}še}}|}}|—}} }}
|}</div>{{#ifeq: {{NAMESPACE}} | {{NS: 0 }} | {{#switch: {{{aspect}}} | pf-impf|p-i|pi= }} }}
{{inflection-box-bottom}}<noinclude>{{documentation}}</noinclude>
7srfxi7zp7ym1hh9aiz8ve65o7a7n5u
ထာမ်ပလိက်:cs-conj-forms/documentation
10
297649
399977
2026-07-23T11:01:26Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} ===Usage=== A template for displaying conjugation forms of Czech verbs. ==Parameters== ===Minimum required parameters=== For most verbs, the following minimum required parameters should suffice to create a complete conjugation table. {| class="wikitable" ! Parameter ! Meaning ! Note |- | pf 1s | present form 1st person singular | not necessary to fill if it differs from 3rd person singular..."
399977
wikitext
text/x-wiki
{{documentation subpage}}
===Usage===
A template for displaying conjugation forms of Czech verbs.
==Parameters==
===Minimum required parameters===
For most verbs, the following minimum required parameters should suffice to create a complete conjugation table.
{| class="wikitable"
! Parameter
! Meaning
! Note
|-
| pf 1s
| present form 1st person singular
| not necessary to fill if it differs from 3rd person singular only by "m" in the end e.g. ''on letí'' (he flies) → ''já letím'' (I fly).
|-
| pf 3s
| present form 3rd person singular
|
|-
|pf 3p
| present form 3rd person plural
| not necessary to fill if it is the same form as 3rd person singular, e.g. ''on letí'' (he flies) → ''oni letí'' (they fly).
|-
| im 2s
| imperative 2nd person singular
|
|-
| past ms
| past participle masculine singular
|
|-
| pass ms
| passive participle masculine singular
| if the passive participle exists
|-
| pass adj
| passive adjective
| if the passive participle exists (i.e. if {{para|pass ms}} parameter is used)
|-
| tr1 pres
| present transgressive masculine singular
| if the present transgressive exists
|-
| tr2 pres
| present transgressive feminine and neuter singular
| if the present transgressive exists
|-
| tr1 past
| past transgressive masculine singular
| if the past transgressive exists
|-
| vn
| verbal noun
|
|-
| aspect
| generates a note about future tense depending on the aspect of the verb
|Possible values:
* "perfective" (or alternatively "perferct", "pf" or "p") for verbs in perfective aspect, whose present forms are used to express future, such as {{m|cs|vejít}}
* "imperfective" (or alternatively "imperfect", "impf", "imp" or "i") for verbs in imperfective aspect, which express future by combination with the auxilliiary "být", such as {{m|cs|brát}}
* "negativeimperfective" (or alternatively "nimpf", "nimp" or "ni") for negative verby in imperfective aspect, which express future by combination with the negative auxilliary "nebýt", such as {{m|cs|nebrat}}. In such a case the parameter "positive" for the positive form of the verb is required too.
* "pf-impf" (or alternatively "p-i" or "pi") for verbs which can be used in both perfective and imperfective aspect, such as {{m|cs|jmenovat}}.
* "pf-nimpf" (or alternatively "p-ni" or "pni") for negative verbs which can be used in both perfective and imperfective aspect, such as {{m|cs|nejmenovat}}. In such a case the parameter "positive" for the positive form of the verb is required too.
|-
| future
| generates a table with future forms for verbs which have future forms
| This parameter is used instead of the "aspect"
Possible values:
*"po", "pů" for words words which express future by these prefixes like {{m|cs|letět}} (''poletím'') or {{m|cs|jít}} (''půjdu'') etc.
* "bud" is only for the word {{m|cs|být}}. It generates not only its future forms (''budu'', ''budeš''...), but also conditional forms (''bych'', ''bys''...).
|-
|positive
|positive form of a negative verb
|Needed only if the future tense of a negative verb is formed by combining a form of {{m|cs|nebýt}} and the infinitive of the positive form of the main verb. Example: the future tense of {{m|cs|nechodit}} is "''nebudu chodit''"
|}
<pre>
{{cs-conj-forms
|pf 1s=
|pf 3s=
|pf 3p=
|im 2s=
|past ms=
|pass ms=
|pass adj=
|tr1 pres=
|tr2 pres=
|tr1 past=
|vn=
|aspect=}}
</pre>
===Examples===
Example for the verb {{m|cs|dávat}}
<pre>
{{cs-conj-forms
|pf 3s = dává
|pf 3p = dávají
|im 2s = dávej
|past ms = dával
|pass ms = dáván
|tr1 pres= dávaje
|tr2 pres= dávajíc
|tr1 past= dávav
|aspect= i}}
</pre>
''Result''
{{cs-conj-forms
|pf 3s=dává
|pf 3p=dávají
|im 2s=dávej
|past ms=dával
|pass ms=dáván
|tr1 pres=dávaje
|tr2 pres=dávajíc
|tr1 past=dávav
|aspect=i}}
====Irregular imperatives====
Some verbs have less regular conjugation and for example plural imperatives cannot be derived simply by adding a suffix to the singular imperative. In such a case, more parameters are recquired, such as for the verb {{m|cs|probdít}}:
<pre>
{{cs-conj-forms
|pf 3s = probdí
|im 2s = probdi
|im 1p = probděme
|im 2p = probděte
|past ms = probděl
|pass ms = probděn
|tr1 past= probděv
|aspect=p}}
</pre>
''Result''
{{cs-conj-forms
|pf 3s=probdí
|im 2s=probdi
|im 1p=probděme
|im 2p=probděte
|past ms=probděl
|pass ms=probděn
|tr1 past=probděv
|aspect=p}}
====Filling automatically left-out parameters====
If some of the parameters mentioned in the section [[#Minimum required parameters|Minimum required parameters]] (except the parameter "future") is missing, all other dependent cells are filled with a dash (—). For example if the parameter "passive ms" is left empty, all cells with passive participles are filled with a dash. This can be overwritten by filling a parameter for the specific form (e. g. <code><nowiki>pass ns</nowiki></code> for passive neuter singular).
The word {{m|cs|tykat}} does not have passive participles with the exception of neuter singular. Leaving <code><nowiki>pass ms</nowiki></code> empty and filling <code><nowiki>pass ns=tykáno</nowiki></code> generates the following table:
{{cs-conj-forms
|pf 3s=tyká
|pf 3p=tykají
|im 2s=tykej
|past ms=tykal
|pass ns=tykáno
|tr1 pres=tykaje
|tr2 pres=tykajíc
|aspect=i}}
====Two forms in one cell====
Some words may need two forms in some of the cells. This can be achieved by filling the particular parameter with both forms in square brackets (e. g. <code><nowiki>ps 1s=[[píši]], [[píšu]]</nowiki></code>), but this possibility cannot be used with parameters on which more cells depend. In such a case another parameter marked with number 2 has to be added:
<pre>
|ps 1s = orám
|ps 1s2 = ořu
|pf 3s = orá
|pf 3s2 = oře
|pf 3p = orají
|pf 3p2 = ořou
|im 2s = orej
|im 2s2 = oř
|past ms= oral
…
</pre>
''Result''
{{cs-conj-forms
|pf 1s=orám
|pf 1s2=ořu
|pf 3s=orá
|pf 3s2=oře
|pf 3p=orají
|pf 3p2=ořou
|im 2s=orej
|im 2s2=oř
|past ms=oral
|pass ms=orán
|tr1 pres=oraje
|tr2 pres=orajíc
|tr1 past=orav
|aspect=i}}
====Colloquial forms of the ''kupovat'' pattern====
The verbs which are conjugated according to the pattern {{m|cs|kupovat}} have also colloquial forms in 1st person present singular and 3r person present plural. These can be shown as follows:
<pre>
|pf 1s=kupuji
|pf 1s col=kupuju
|pf 3s=kupuje
|pf 3p=kupují
|pf 3p col=kupujou
…
</pre>
''Result''
{{cs-conj-forms
|pf 1s=kupuji
|pf 1s col=kupuju
|pf 3s=kupuje
|pf 3p=kupují
|pf 3p col=kupujou
|im 2s=kupuj
|past ms=kupoval
|pass ms=kupován
|tr1 pres=kupuje
|tr2 pres=kupujíc
|aspect=i}}
====Future tense====
Most verbs do not have distinct present and future forms in Czech language and so the table has just a short note on forming the future tense for the particular verb. Perfective verbs form use their present forms to express the future, which is indicated in the table as follows:
<pre>
|pf 3s = pustí
|im 2s = pusť
…
|aspect = p
</pre>
''Result''
{{cs-conj-forms
|pf 3s=pustí
|im 2s=pusť
|past ms=pustil
|pass ms=puštěn
|tr1 past=pustiv
|aspect=p}}
Imperfective verbs usually form the future in combination with {{m|cs|být}}:
<pre>
|pf 1s=beru
|pf 3s=bere
|pf 3p=berou
|im 2s=ber
...
|aspect = i}}
</pre>
''Result''
{{cs-conj-forms
|pf 1s=beru
|pf 3s=bere
|pf 3p=berou
|im 2s=ber
|past ms=bral
|pass ms=brán
|tr1 pres=bera
|tr2 pres=berouc
|tr1 past=
|aspect=i}}
Negative imperfective verbs need one more parameter, the positive form of the verb:
<pre>
|pf 3s=nemá
|pf 3p=nemají
|im 2s=neměj
...
|aspect=ni
|positive=mít}}
</pre>
''Result''
{{cs-conj-forms
|pf 3s=nemá
|pf 3p=nemají
|im 2s=neměj
|past ms=neměl
|tr1 pres=nemaje
|tr2 pres=nemajíc
|aspect=ni
|positive=mít}}
Some verbs can be used in both perfective and imperfective aspects, such as {{m|cs|jmenovat}}:
<pre>
...
|pf 3s=jmenuje
|pf 3p=jmenují
...
|aspect=p-i}}
</pre>
''Result''
{{cs-conj-forms
|pf 1s=jmenuji
|pf 1s col=jmenuju
|pf 3s=jmenuje
|pf 3p=jmenují
|pf 3p col=jmenujou
|im 2s=jmenuj
|past ms=jmenoval
|pass ms=jmenován
|tr1 pres=jmenuje
|tr2 pres=jmenujíc
|tr1 past=jmenovav
|aspect=p-i}}
Some negative verbs can also be used in both perfective and imperfective aspects, such as {{m|cs|nejmenovat}}:
<pre>
...
|pf 3s=nejmenuje
|pf 3p=nejmenují
...
|aspect=p-ni
|positive=jmenovat}}
</pre>
''Result''
{{cs-conj-forms
|pf 1s=nejmenuji
|pf 1s col=nejmenuju
|pf 3s=nejmenuje
|pf 3p=nejmenují
|pf 3p col=nejmenujou
|im 2s=nejmenuj
|past ms=nejmenoval
|pass ms=nejmenován
|tr1 pres=nejmenuje
|tr2 pres=nejmenujíc
|tr1 past=nejmenovav
|aspect=p-ni
|positive=jmenovat}}
There are a few exceptions of verbs which have future forms made by a prefix:
<pre>
|pf 3s=letí
|im 2s=leť
...
|future=po}}
</pre>
''Result''
{{User:Jan.Kamenicek/Experiment
|pf 3s=letí
|im 2s=leť
|past ms=letěl
|tr1 pres=letě
|tr2 pres=letíc
|future=po}}
Negative verbs which have future do not need the parameter "future" but need other additional parameters:
<pre>
|pf 3s=neletí
|im 2s=neleť
|ff 3s=nepoletí
...
</pre>
''Result''
{{cs-conj-forms
|pf 3s=neletí
|im 2s=neleť
|ff 3s=nepoletí
|past ms=neletěl
|tr1 pres=neletě
|tr2 pres=neletíc}}
<pre>
|pf 1s=nejedu
|pf 3s=nejede
|pf 3p=nejedou
|im 2s=nejeď
|ff 1s=nepojedu
|ff 3s=nepojede
|ff 3p=nepojedou
...
</pre>
''Result''
{{cs-conj-forms
|pf 1s=nejedu
|pf 3s=nejede
|pf 3p=nejedou
|im 2s=nejeď
|ff 1s=nepojedu
|ff 3s=nepojede
|ff 3p=nepojedou
|past ms=nejel
|tr1 pres=nejeda
|tr2 pres=nejedouc}}
===All parameters===
Here is a list of all parameters.
{| class="wikitable"
! Parameter
! Meaning
|-
| pf 1s
| present form 1st person singular
|-
| pf 1s2
| alternative present form 1st person singular
|-
| pf 1s col
| colloquial present form 1st person singular
|-
| pf 2s
| present form 2nd person singular
|-
| pf 2s2
| alternative present form 2nd person singular
|-
| pf 2s col
| colloquial present form 2nd person singular
|-
| pf 3s
| present form 3rd person singular
|-
| pf 3s2
| alternative present form 3rd person singular
|-
| pf 3s col
| colloquial present form 3rd person singular
|-
| pf 1p
| present form 1st person plural
|-
| pf 1p2
| alternative present form 1st person plural
|-
| pf 1p col
| colloquial present form 1st person plural
|-
| pf 2p
| present form 2nd person plural
|-
| pf 2p2
| alternative present form 2nd person plural
|-
| pf 2p col
| colloquial present form 2nd person plural
|-
| pf 3p
| present form 3rd person plural
|-
| pf 3p2
| alternative present form 3rd person plural
|-
| pf 3p col
| colloquial present form 3rd person plural
|-
| im 2s
| imperative 2nd person singular
|-
| im 2s col
| colloquial imperative 2nd person singular, generates also automatically 1st and 2nd person plural
|-
| im 2s2
| alternative form of imperative 2nd person singular
|-
| im 1p
| imperative 1st person singular
|-
| im 1p2
| alternative form of imperative 1st person singular
|-
| im 2p
| imperative 2nd person plural
|-
| im 2p2
| alternative form of imperative 2nd person plural
|-
| ff 1s
| future 1st person singular
|-
| ff 1s2
| alternative form of future 1st person singular
|-
| ff 3s
| future 3rd person singular
|-
| ff 3p
| future 3rd person plural
|-
| ff 3p2
| alternative form of future 3rd person plural
|-
| past ms
| past participle masculine singular
|-
| past ms2
| alternative form of past participle masculine singular, generates all other masculine, feminine and neuter alternative forms as well
|-
| past ms3
| one more alternative form of past participle masculine singular, generates all other masculine, feminine and neuter alternative forms as well
|-
| past fs
| past participle feminine singular
|-
| past ns
| past participle neuter singular
|-
| past map
| past participle masculine animate plural
|-
| past mip
| past participle masculine inanimate plural
|-
| past fp
| past participle feminine plural
|-
| past np
| past participle neuter plural
|-
| pass ms
| passive participle masculine singular
|-
| pass ms2
| alternative form of passive participle masculine singular, generates all other masculine, feminine and neuter alternative forms as well
|-
| pass ms3
| one more alternative form of passive participle masculine singular, generates all other masculine, feminine and neuter alternative forms as well
|-
| pass fs
| passive participle feminine singular
|-
| pass ns
| passive participle neuter singular
|-
| pass ns
| alternative passive participle neuter singular
|-
| pass map
| passive participle masculine animate plural
|-
| pass mip
| passive participle masculine inanimate plural
|-
| pass fp
| passive participle feminine plural
|-
| pass np
| passive participle neuter plural
|-
| pass adj
| passive adjective
|-
| tr1 pres
| present transgressive masculine singular
|-
| tr1 pres2
| alternative form of present transgressive masculine singular
|-
| tr2 pres
| present transgressive feminine and neuter singular
|-
| tr2 pres2
| alternative form of present transgressive feminine and neuter singular
|-
| tr3 pres
| present transgressive plural
|-
| tr1 past
| past transgressive masculine singular
|-
| tr1 past2
| alternative past transgressive masculine singular (generates other alternative past transgressive forms too)
|-
| tr1 past3
| one more alternative past transgressive masculine singular (generates other alternative past transgressive forms too)
|-
| tr2 past
| past transgressive feminine and neuter singular
|-
| tr3 past
| past transgressive plural
|-
| vn
| verbal noun
|-
| aspect
| generates a note about future tense (see [[#Minimum recquired parameters|above]])
|-
| future
| enables to generate table with future forms for the few verbs which have future forms
|-
| positive
| positive form of a negative imperfective verb, (see [[#Minimum recquired parameters|above]])
|}
<pre>
{{cs-conj-forms
|pf 1s=
|pf 1s2=
|pf 1s col=
|pf 2s=
|pf 2s2=
|pf 2s col=
|pf 3s=
|pf 3s2=
|pf 3s col=
|pf 1p=
|pf 1p2=
|pf 1p col=
|pf 2p=
|pf 2p2=
|pf 2p col=
|pf 3p=
|pf 3p2=
|pf 3p col=
|im 1p=
|im 1p2=
|im 2s=
|im 2s2=
|im 2s col=
|im 2p=
|im 2p2=
|ff 1s=
|ff 1s2=
|ff 3s=
|ff 3p=
|ff 3p2=
|past ms=
|past ms2=
|past ms3=
|past fs=
|past ns=
|past map=
|past mip=
|past fp=
|past np=
|pass ms=
|pass ms2=
|pass ms3=
|pass fs=
|pass ns=
|pass ns2=
|pass map=
|pass mip=
|pass fp=
|pass np=
|pass adj=
|tr1 pres=
|tr1 pres2=
|tr2 pres=
|tr2 pres2=
|tr3 pres=
|tr1 past=
|tr1 past2=
|tr1 past3=
|tr2 past=
|tr3 past=
|vn=
|aspect=
|future=
|positive=
}}
</pre>
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ချက်ခ်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏကြိယာဂမၠိုၚ်| ]]
</includeonly>
3taggh5uclrz35vz3gp9y7svtcrgc9d
rozzlobit
0
297650
399978
2026-07-23T11:16:52Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ချက်ခ်== {{was wotd|၂၀၂၆|ဂျူလာင်|၂၆}} ===ဗွဟ်ရမ္သာၚ်=== * {{cs-IPA}} * {{audio|cs|LL-Q9056 (ces)-Ghost4Man-{{pagename}}.wav}} ===ကြိယာ=== {{cs-verb|a=pf|impf=zlobit}} # သကဵုမကၠောန်သ္ပစိုတ်က္တဵု၊ သကဵုဒေါသတိတ်။ # သကဵုဂွံဒုၚ်သိုၚ်မဒှ..."
399978
wikitext
text/x-wiki
==ချက်ခ်==
{{was wotd|၂၀၂၆|ဂျူလာင်|၂၆}}
===ဗွဟ်ရမ္သာၚ်===
* {{cs-IPA}}
* {{audio|cs|LL-Q9056 (ces)-Ghost4Man-{{pagename}}.wav}}
===ကြိယာ===
{{cs-verb|a=pf|impf=zlobit}}
# သကဵုမကၠောန်သ္ပစိုတ်က္တဵု၊ သကဵုဒေါသတိတ်။
# သကဵုဂွံဒုၚ်သိုၚ်မဒှ်ဒေါသ။
====သမ္ဗန္ဓ====
{{cs-conj-pros-it|rozzl|o|b}}
r9yw4p8u3db2mv9srs2k8o3vfinbo9x
ဝိက်ရှေန်နရဳ:မအရေဝ်သွက်တ္ၚဲဏအ်/၂၀၂၆/ဂျူလာင် ၂၆
4
297651
399979
2026-07-23T11:18:41Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{WOTD|rozzlobit|ကြိယာ| သကဵုမကၠောန်သ္ပစိုတ်က္တဵု၊ သကဵုဒေါသတိတ်။ # သကဵုဂွံဒုၚ်သိုၚ်မဒှ်ဒေါသ။|audio=LL-Q9056 (ces)-Ghost4Man-rozzlobit.wav|ဂျူလာင်|၂၆}}"
399979
wikitext
text/x-wiki
{{WOTD|rozzlobit|ကြိယာ| သကဵုမကၠောန်သ္ပစိုတ်က္တဵု၊ သကဵုဒေါသတိတ်။
# သကဵုဂွံဒုၚ်သိုၚ်မဒှ်ဒေါသ။|audio=LL-Q9056 (ces)-Ghost4Man-rozzlobit.wav|ဂျူလာင်|၂၆}}
nh01kllptx890bok7vx5nz83m7lg2hu
ကဏ္ဍ:ကာရန်:ပဝ်လာန်/ɔba
14
297652
399980
2026-07-23T11:23:08Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » :ကဏ္ဍ:ကာ..."
399980
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -ɔba
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် [[ကာရန်:ပဝ်လာန်/ɔba|-ɔba]] ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ɔba]]
2w6r4od61my1cuvd77yl7r70q76bj1a
ကာရန်:ပဝ်လာန်/ɔba
106
297653
399981
2026-07-23T11:24:29Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{rhymes nav|pl|ɔ|ba}} ==ဗွဟ်ရမ္သာၚ်== *{{IPAchar|/-ɔba/}} ===ဝဏ္ဏမွဲ=== ===ဝဏ္ဏၜါ=== ===ဝဏ္ဏပိ=== ===ဝဏ္ဏပန်=== ===ဝဏ္ဏမသုန်=== ===ဝဏ္ဏတရဴ=== ===ဝဏ္ဏထပှ်=== ===ဝဏ္ဏဒ္စာံ=== ===ဝဏ္ဏဒ္စိတ်=== ===ဝဏ္ဏစှ်=== ===ဝဏ္ဏစှ်မွဲ=== ==..."
399981
wikitext
text/x-wiki
{{rhymes nav|pl|ɔ|ba}}
==ဗွဟ်ရမ္သာၚ်==
*{{IPAchar|/-ɔba/}}
===ဝဏ္ဏမွဲ===
===ဝဏ္ဏၜါ===
===ဝဏ္ဏပိ===
===ဝဏ္ဏပန်===
===ဝဏ္ဏမသုန်===
===ဝဏ္ဏတရဴ===
===ဝဏ္ဏထပှ်===
===ဝဏ္ဏဒ္စာံ===
===ဝဏ္ဏဒ္စိတ်===
===ဝဏ္ဏစှ်===
===ဝဏ္ဏစှ်မွဲ===
===ဝဏ္ဏစှ်ၜါ===
===ဝဏ္ဏစှ်ပိ===
===ဝဏ္ဏစှ်ပန်===
===ဝဏ္ဏစှ်သုန်===
===ဝဏ္ဏစှ်တရဴ===
===ဝဏ္ဏစှ်ထပှ်===
===ဝဏ္ဏစှ်ဒ္စာံ===
===ဝဏ္ဏစှ်ဒ္စိတ်===
===ဝဏ္ဏၜါစှော်===
fb6vz15e0zq7klczruuzxzqopve6n13
złobą
0
297654
399982
2026-07-23T11:25:56Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zloba|złoba|żłoba}} ==ပဝ်လာန်== ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr}} ===နာမ်=== {{head|pl|noun form|g=f}} # {{inflection of|pl|złoba||ins|s}}"
399982
wikitext
text/x-wiki
{{also|zloba|złoba|żłoba}}
==ပဝ်လာန်==
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr}}
===နာမ်===
{{head|pl|noun form|g=f}}
# {{inflection of|pl|złoba||ins|s}}
0rles986gpo41yhxrm2de6u96fk7rz9
ကဏ္ဍ:ကာရန်:ပဝ်လာန်/ɔbɔw̃
14
297655
399983
2026-07-23T11:26:58Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » :ကဏ္ဍ:ကာ..."
399983
wikitext
text/x-wiki
[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]] » [[:ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ကာရန်ဂမၠိုၚ်]] » -ɔbɔw̃
:စရၚ်မဆေၚ်စပ်ကဵုဝေါဟာ[[:ကဏ္ဍ:ဘာသာပဝ်လာန်|ပဝ်လာန်]]မနွံကာရန် ɔbɔw̃ ဂမၠိုၚ်။
[[ကဏ္ဍ:ကာရန်:ပဝ်လာန်|ɔbɔw̃]]
iw04hb562bb4c554645d8lzft9zguo3
złoba
0
297656
399984
2026-07-23T11:31:54Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zloba|złobą|żłoba}} ==ပဝ်လာန်== ===နိရုတ်=== {{inh+|pl|zlw-opl|[[zgłoba]], [[złoba]]}}၊ နူကဵုဝေါဟာ {{inh|pl|sla-pro|*zъloba}} ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr}} ===နာမ်=== {{pl-noun|f}} # {{lb|pl|obsolete}} စိုတ်ပစ္ဆရိယ၊ ပရေၚ်ဒေပ်သ္ကဲ။ #: {{syn|pl|przewrotność|złośliwość}..."
399984
wikitext
text/x-wiki
{{also|zloba|złobą|żłoba}}
==ပဝ်လာန်==
===နိရုတ်===
{{inh+|pl|zlw-opl|[[zgłoba]], [[złoba]]}}၊ နူကဵုဝေါဟာ {{inh|pl|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr}}
===နာမ်===
{{pl-noun|f}}
# {{lb|pl|obsolete}} စိုတ်ပစ္ဆရိယ၊ ပရေၚ်ဒေပ်သ္ကဲ။
#: {{syn|pl|przewrotność|złośliwość}}
====လဟုတ်စှ်ေ====
{{pl-decl-noun-f|tantum=s}}
52lyc020p3heedjshdhosm8wmvr7897
ကဏ္ဍ:ဝေါဟာပဝ်လာန်မၞုံကဵုဒုၚ်စသိုၚ်အရီုမဟွံဂတာပ်ခေတ်
14
297657
399985
2026-07-23T11:32:37Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာပဝ်လာန်]]"
399985
wikitext
text/x-wiki
[[ကဏ္ဍ:ဘာသာပဝ်လာန်]]
lqkk8sh9o9qyqpe25zynszbn308h6l1
ထာမ်ပလိက်:pl-decl-noun-f
10
297658
399986
2026-07-23T11:33:55Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|f}}<noinclude>{{documentation}}</noinclude>"
399986
wikitext
text/x-wiki
{{safesubst:<noinclude/>#invoke:pl-noun|template_decl_pattern|f}}<noinclude>{{documentation}}</noinclude>
dgznhs6opmbnfr0vvc8sse6f6yuuo1t
ထာမ်ပလိက်:pl-decl-noun-f/documentation
10
297659
399987
2026-07-23T11:35:39Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} Declension table template for all Polish feminine nouns with noun-like declension ===Usage=== <nowiki>====လဟုတ်စှ်ေ==== {{pl-decl-noun-f||||}}</nowiki> The declension depends on the number of parameters and the ending of the lemma. Special declensions are created for nouns ending in -ni and -ia. For nouns where the lemma form does not end in -a, -y, -i or -e, a consonant..."
399987
wikitext
text/x-wiki
{{documentation subpage}}
Declension table template for all Polish feminine nouns with noun-like declension
===Usage===
<nowiki>====လဟုတ်စှ်ေ====
{{pl-decl-noun-f||||}}</nowiki>
The declension depends on the number of parameters and the ending of the lemma. Special declensions are created for nouns ending in -ni and -ia. For nouns where the lemma form does not end in -a, -y, -i or -e, a consonant-final declension is generated.
If two parameters are given, the normal feminine declension is always created, and ending matches are ignored; this is useful for rare nouns that end in -ia but have native declension (without geminated ''i'' in the genitive, e.g. {{m|pl|konopia}}. If three or more parameters are given, they specify a consonant-final declension.
* {{para|1}} '''word stem''' (usually optional)
* {{para|2}} '''last consonant''' of the word or '''digraph''', as it appears in the nominative plural
* {{para|3}} if specified, gives the '''nominative plural ending''' for a noun ending in a consonant
* {{para|4}} irregular '''nominative singular''' for nouns ending in a consonant
If the first and/or second parameters are omitted, they will be automatically guessed based on a list of known feminine noun endings.
The vocative singular form generated will always end in -o, which is incorrect for some female given names and nouns referring to persons, such as {{m|pl|babunia}}. Use the {{para|vocs}} parameter to correct this.
===Examples===
If the example is in ''italics'', it means the parameters are given only for exposition and the fully automatic form {{temp|pl-decl-noun-f}} (with {{para|tantum}}, if necessary) will generate the correct declension in that case.
* ''[[praca]]'': {{temp|pl-decl-noun-f|pra|c}}
* ''[[budowla]]'': {{temp|pl-decl-noun-f|budow|l}}
* [[krowa]]: {{temp|pl-decl-noun-f|kro|w|genp=krów}}
* ''[[mistrzyni]]'': {{temp|pl-decl-noun-f|lemma=mistrzyni}}
* [[konopia]]: {{temp|pl-decl-noun-f|kono|pi}}
* [[skrobia]]: {{temp|pl-decl-noun-f|skro|bi}}
* ''[[mafia]]'': {{temp|pl-decl-noun-f|lemma=mafia}}
* ''[[twarz]]'': {{temp|pl-decl-noun-f|twa|rz|e}}
* ''[[noc]]'': {{temp|pl-decl-noun-f|no|c|e}}
* ''[[otchłań]]'': {{temp|pl-decl-noun-f|otchła|ni|e}}
* [[sól]]: {{temp|pl-decl-noun-f|so|l|e|sól}}
* [[brew]]: {{temp|pl-decl-noun-f|br|wi||brew}}
<includeonly>
[[ကဏ္ဍ:ထာမ်ပလိက်ပဝ်လာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏနာမ်ဂမၠိုၚ်|f]]</includeonly>
6ri4v33vlvmwqn5bdo7tx53bcwclxvw
zgłoba
0
297660
399988
2026-07-23T11:39:56Z
咽頭べさ
33
ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|zgłobą}} ==ပဝ်လာန်== ===နိရုတ်=== {{inh+|pl|zlw-opl|[[zgłoba]], [[złoba]]}}၊ နူကဵုဝေါဟာ {{inh|pl|sla-pro|*zъloba}} ===ဗွဟ်ရမ္သာၚ်=== {{pl-pr}} ===နာမ်=== {{pl-noun|f}} # {{lb|pl|obsolete}} ပရေၚ်စိုတ်မထုဲဂရုဲ၊ ပရေၚ်ဒှ်သောက။ #: {{syn|pl|ambaras|kłopot}} ====လ..."
399988
wikitext
text/x-wiki
{{also|zgłobą}}
==ပဝ်လာန်==
===နိရုတ်===
{{inh+|pl|zlw-opl|[[zgłoba]], [[złoba]]}}၊ နူကဵုဝေါဟာ {{inh|pl|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr}}
===နာမ်===
{{pl-noun|f}}
# {{lb|pl|obsolete}} ပရေၚ်စိုတ်မထုဲဂရုဲ၊ ပရေၚ်ဒှ်သောက။
#: {{syn|pl|ambaras|kłopot}}
====လဟုတ်စှ်ေ===
{{pl-decl-noun-f}}
9vkvjpb7o84ppu538j3nfowyhhlir75
399989
399988
2026-07-23T11:40:21Z
咽頭べさ
33
399989
wikitext
text/x-wiki
{{also|zgłobą}}
==ပဝ်လာန်==
===နိရုတ်===
{{inh+|pl|zlw-opl|[[zgłoba]], [[złoba]]}}၊ နူကဵုဝေါဟာ {{inh|pl|sla-pro|*zъloba}}
===ဗွဟ်ရမ္သာၚ်===
{{pl-pr}}
===နာမ်===
{{pl-noun|f}}
# {{lb|pl|obsolete}} ပရေၚ်စိုတ်မထုဲဂရုဲ၊ ပရေၚ်ဒှ်သောက။
#: {{syn|pl|ambaras|kłopot}}
===လဟုတ်စှ်ေ===
{{pl-decl-noun-f}}
bdht2ithet3iumu5xykdtz198atl3i4