ဝိက်ရှေန်နရဳ 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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" args.short_n = args.short_n or "&mdash;" args.short_f = args.short_f or "&mdash;" args.short_p = args.short_p or "&mdash;" 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 "&mdash;" 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 "&mdash;" 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'&#39;</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'&#39;</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 || &mdash; || &mdash; || полпути́ || |} ===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|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ဗဳဇဂကူ''' | {{l-self|sh|{{{gs|{{{2|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပြကမ္မကာရက''' | {{l-self|sh|{{{ds|{{{3|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ကမ္မကာရက''' | {{l-self|sh|{{{as|{{{4|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပရေၚ်ဂယိုၚ်လမျီု''' | {{l-self|sh|{{{vs|{{{5|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ခၞံဗဒှ်ဌာန်မတန်တဴ''' | {{l-self|sh|{{{ls|{{{6|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်''' | {{l-self|sh|{{{is|{{{7|&mdash;}}}}}}}} |}</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|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ဗဳဇဂကူ''' | {{l-self|sh|{{{gs|{{{2|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပြကမ္မကာရက''' | {{l-self|sh|{{{ds|{{{3|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ကမ္မကာရက''' | {{l-self|sh|{{{as|{{{4|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ပရေၚ်ဂယိုၚ်လမျီု''' | {{l-self|sh|{{{vs|{{{5|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''ခၞံဗဒှ်ဌာန်မတန်တဴ''' | {{l-self|sh|{{{ls|{{{6|&mdash;}}}}}}}} |- ! style="background:var(--wikt-palette-lighterblue, #ebf4ff);" | '''တိၚ်တိုက်ကပေါတ်ကွိၚ်ကွိုက်''' | {{l-self|sh|{{{is|{{{7|&mdash;}}}}}}}} |}</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|каву́н&lt;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|шко́ла&lt;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}}}}}|&mdash;}} | {{#if:{{{ind_f|}}}|{{l-self|mk|{{{ind_f}}}|accel-form=indef{{!}}f{{!}}sg}}|&mdash;}} | {{#if:{{{ind_n|}}}|{{l-self|mk|{{{ind_n}}}|accel-form=indef{{!}}n{{!}}sg}}|&mdash;}} | {{#if:{{{ind_pl|}}}|{{l-self|mk|{{{ind_pl}}}|accel-form=indef{{!}}pl}}|&mdash;}} |- ! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ် | {{#if:{{{def_unsp_m|}}}|{{l-self|mk|{{{def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg}}|&mdash;}} | {{#if:{{{def_unsp_f|}}}|{{l-self|mk|{{{def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg}}|&mdash;}} | {{#if:{{{def_unsp_n|}}}|{{l-self|mk|{{{def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg}}|&mdash;}} | {{#if:{{{def_unsp_pl|}}}|{{l-self|mk|{{{def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl}}|&mdash;}} |- ! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ် | {{#if:{{{def_prox_m|}}}|{{l-self|mk|{{{def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg}}|&mdash;}} | {{#if:{{{def_prox_f|}}}|{{l-self|mk|{{{def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg}}|&mdash;}} | {{#if:{{{def_prox_n|}}}|{{l-self|mk|{{{def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg}}|&mdash;}} | {{#if:{{{def_prox_pl|}}}|{{l-self|mk|{{{def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl}}|&mdash;}} |- ! ဇမ္ၚောဲမချိုတ်ပၠိုတ် | {{#if:{{{def_dist_m|}}}|{{l-self|mk|{{{def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg}}|&mdash;}} | {{#if:{{{def_dist_f|}}}|{{l-self|mk|{{{def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg}}|&mdash;}} | {{#if:{{{def_dist_n|}}}|{{l-self|mk|{{{def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg}}|&mdash;}} | {{#if:{{{def_dist_pl|}}}|{{l-self|mk|{{{def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl}}|&mdash;}} |- | class="separator" colspan="999" | |- ! class="outer" | ပတဝ်ပတုပ်ရံၚ် ! ပုလ္လိၚ် ! ဣတ္တိလိၚ် ! နပုလ္လိၚ် ! ကိုန်ဗဟုဝစ် |- ! ဟွံချိုတ်ပၠိုတ် | {{#if:{{{c_ind_m|}}}|{{l-self|mk|{{{c_ind_m}}}|accel-form=indef{{!}}m{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_ind_f|}}}|{{l-self|mk|{{{c_ind_f}}}|accel-form=indef{{!}}f{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_ind_n|}}}|{{l-self|mk|{{{c_ind_n}}}|accel-form=indef{{!}}n{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_ind_pl|}}}|{{l-self|mk|{{{c_ind_pl}}}|accel-form=indef{{!}}pl{{!}}comd}}|&mdash;}} |- ! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ် | {{#if:{{{c_def_unsp_m|}}}|{{l-self|mk|{{{c_def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_unsp_f|}}}|{{l-self|mk|{{{c_def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_unsp_n|}}}|{{l-self|mk|{{{c_def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_unsp_pl|}}}|{{l-self|mk|{{{c_def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl{{!}}comd}}|&mdash;}} |- ! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ် | {{#if:{{{c_def_prox_m|}}}|{{l-self|mk|{{{c_def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_prox_f|}}}|{{l-self|mk|{{{c_def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_prox_n|}}}|{{l-self|mk|{{{c_def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_prox_pl|}}}|{{l-self|mk|{{{c_def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl{{!}}comd}}|&mdash;}} |- ! ဇမ္ၚောဲမချိုတ်ပၠိုတ် | {{#if:{{{c_def_dist_m|}}}|{{l-self|mk|{{{c_def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_dist_f|}}}|{{l-self|mk|{{{c_def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_dist_n|}}}|{{l-self|mk|{{{c_def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg{{!}}comd}}|&mdash;}} | {{#if:{{{c_def_dist_pl|}}}|{{l-self|mk|{{{c_def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl{{!}}comd}}|&mdash;}} |- | class="separator" colspan="999" | |- ! class="outer" | တၞုၚ်တၞောတ် ! ပုလ္လိၚ် ! ဣတ္တိလိၚ် ! နပုလ္လိၚ် ! plural |- ! ဟွံချိုတ်ပၠိုတ် | {{#if:{{{s_ind_m|}}}|{{l-self|mk|{{{s_ind_m}}}|accel-form=indef{{!}}m{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_ind_f|}}}|{{l-self|mk|{{{s_ind_f}}}|accel-form=indef{{!}}f{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_ind_n|}}}|{{l-self|mk|{{{s_ind_n}}}|accel-form=indef{{!}}n{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_ind_pl|}}}|{{l-self|mk|{{{s_ind_pl}}}|accel-form=indef{{!}}pl{{!}}supd}}|&mdash;}} |- ! ဟွံဂွံစၟတ်သမ္တီလဝ်မချိုတ်ပၠိုတ် | {{#if:{{{s_def_unsp_m|}}}|{{l-self|mk|{{{s_def_unsp_m}}}|accel-form=unspecified{{!}}def{{!}}m{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_unsp_f|}}}|{{l-self|mk|{{{s_def_unsp_f}}}|accel-form=unspecified{{!}}def{{!}}f{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_unsp_n|}}}|{{l-self|mk|{{{s_def_unsp_n}}}|accel-form=unspecified{{!}}def{{!}}n{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_unsp_pl|}}}|{{l-self|mk|{{{s_def_unsp_pl}}}|accel-form=unspecified{{!}}def{{!}}pl{{!}}supd}}|&mdash;}} |- ! ပရေၚ်ကြပ်မချိုတ်ပၠိုတ် | {{#if:{{{s_def_prox_m|}}}|{{l-self|mk|{{{s_def_prox_m}}}|accel-form=prox{{!}}def{{!}}m{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_prox_f|}}}|{{l-self|mk|{{{s_def_prox_f}}}|accel-form=prox{{!}}def{{!}}f{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_prox_n|}}}|{{l-self|mk|{{{s_def_prox_n}}}|accel-form=prox{{!}}def{{!}}n{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_prox_pl|}}}|{{l-self|mk|{{{s_def_prox_pl}}}|accel-form=prox{{!}}def{{!}}pl{{!}}supd}}|&mdash;}} |- ! ဇမ္ၚောဲမချိုတ်ပၠိုတ် | {{#if:{{{s_def_dist_m|}}}|{{l-self|mk|{{{s_def_dist_m}}}|accel-form=distal{{!}}def{{!}}m{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_dist_f|}}}|{{l-self|mk|{{{s_def_dist_f}}}|accel-form=distal{{!}}def{{!}}f{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_dist_n|}}}|{{l-self|mk|{{{s_def_dist_n}}}|accel-form=distal{{!}}def{{!}}n{{!}}sg{{!}}supd}}|&mdash;}} | {{#if:{{{s_def_dist_pl|}}}|{{l-self|mk|{{{s_def_dist_pl}}}|accel-form=distal{{!}}def{{!}}pl{{!}}supd}}|&mdash;}} {{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'&#39;</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'&#39;</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}} &rarr; {{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}} &rarr; 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}} &rarr; 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|}}}||&mdash;}}}}{{#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}}}}}|&mdash;}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}} !နာမဝိသေသနမဒုၚ်ကေတ် |{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|&mdash;}}|&mdash;}}{{#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}}|&mdash;}}}}{{#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}}}}}&nbsp;(''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|&mdash;}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}| {{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || &mdash; ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၂ | {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|&mdash;}}}}{{#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}}}š}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|&mdash;}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|&mdash;}} }}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၃ | {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|&mdash;}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| &mdash;}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || &mdash; || &mdash; {{#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}}}}}&nbsp;(''[[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}}}}}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}}}}}}}}{{#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}}|&mdash;}}}}}}}}{{#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}}|}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}}}}|}}|&mdash;}} |- !ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ် |{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|&mdash;}}{{#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}}|}}|&mdash;}} }} |- !ကိုန်ဗဟုဝစ် | {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|&mdash;}} }}{{#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}}|}}|&mdash;}} }} |}</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|}}}||&mdash;}}}}{{#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}}}}}|&mdash;}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}} !နာမဝိသေသနမဒုၚ်ကေတ် |{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|&mdash;}}|&mdash;}}{{#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}}|&mdash;}}}}{{#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}}}}}&nbsp;(''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|&mdash;}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}| {{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || &mdash; ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၂ | {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|&mdash;}}}}{{#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}}}š}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|&mdash;}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|&mdash;}} }}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၃ | {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|&mdash;}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| &mdash;}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || &mdash; || &mdash; {{#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}}}}}&nbsp;(''[[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}}}}}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}}}}}}}}{{#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}}|&mdash;}}}}}}}}{{#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}}|}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}}}}|}}|&mdash;}} |- !ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ် |{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|&mdash;}}{{#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}}|}}|&mdash;}} }} |- !ကိုန်ဗဟုဝစ် | {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|&mdash;}} }}{{#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}}|}}|&mdash;}} }} |}</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|}}}||&mdash;}}}}{{#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}}}}}|&mdash;}}{{#if:{{{vn2|}}}|, {{l|cs|2={{{vn2}}}}}|}} !နာမဝိသေသနမဒုၚ်ကေတ် |{{#if:{{{pass ms|}}}|{{#if:{{{pass adj|}}}|{{l|cs|2={{{pass adj}}}}}|&mdash;}}|&mdash;}}{{#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}}|&mdash;}}}}{{#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}}}}}&nbsp;(''[[colloquial|coll.]]'')}}||{{#if:{{{pf 1p|}}}|{{l|cs|2={{{pf 1p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}me}}|&mdash;}}}}{{#if:{{{pf 1p2|}}}|, {{l|cs|2={{{pf 1p2}}}}}| {{#if:{{{pf 3s2|}}}|{{#switch: {{{pf 3s2}}} | jest=| |, {{l|cs|2={{{pf 3s2}}}me}} }}|}}}} || &mdash; ||{{#if:{{{im 1p|}}}|{{l|cs|2={{{im 1p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}me}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၂ | {{#if:{{{pf 2s|}}}|{{l|cs|2={{{pf 2s}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}š}}|&mdash;}}}}{{#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}}}š}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 2p|}}}|{{l|cs|2={{{pf 2p}}}}}|{{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}te}}|&mdash;}}}}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}}}|&mdash;}}{{#if:{{{im 2s2|}}}|, {{l|cs|2={{{im 2s2}}}}}|}}{{#if:{{{im 2s col|}}}|,<br/> {{l|cs|2={{{im 2s col}}} }}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{im 2p|}}}|{{l|cs|2={{{im 2p}}}}}|{{#if:{{{im 2s|}}}|{{l|cs|2={{{im 2s}}}te}}|&mdash;}} }}{{#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}}&nbsp;(''[[colloquial|coll.]]'')}} |- !ပူဂဵုမရနုက်ကဵု ၃ | {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}}}}|&mdash;}}{{#if:{{{pf 3s2|}}}|, {{l|cs|2={{{pf 3s2}}}}}|}}{{#if:{{{pf 3s col|}}}|,<br/> {{l|cs|2={{{pf 3s col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || {{#if:{{{pf 3p|}}}|{{l|cs|2={{{pf 3p}}}}}| {{#if:{{{pf 3s|}}}|{{l|cs|2={{{pf 3s}}} }}| &mdash;}} }}{{#if:{{{pf 3p2|}}}|, {{l|cs|2={{{pf 3p2}}}}}|}}{{#if:{{{pf 3p col|}}}|,<br/> {{l|cs|2={{{pf 3p col}}}}}&nbsp;(''[[colloquial|coll.]]'')}} || &mdash; || &mdash; {{#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}}}}}&nbsp;(''[[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}}}}}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}} }}&nbsp;(''[[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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}}}}}}}}{{#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}}|&mdash;}}}}}}}}{{#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}}|}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}|&mdash;}} }}{{#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}}}}}|&mdash;}}{{#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}}}}}|}}|&mdash;}} |- !ဣတ္တိလိၚ် + နပုလ္လိၚ်ကိုန်ဨကဝုစ် |{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}}}|&mdash;}}{{#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}}|}}|&mdash;}} }} |- !ကိုန်ဗဟုဝစ် | {{#if:{{{tr3 pres |}}}|{{l|cs|2={{{tr3 pres}}}}}|{{#if:{{{tr2 pres|}}}|{{l|cs|2={{{tr2 pres}}}e}}|&mdash;}} }}{{#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}}|}}|&mdash;}} }} |}</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) &rarr; ''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) &rarr; ''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